Hacker News new | ask | show | jobs
by adamonduty 4834 days ago
So correct me if I'm wrong...

Slide 13 shows an example memory recycler. I understand the concept, but it uses a Go List to keep track of the elements. list.PushFront() allocates a new object on every invocation (see http://golang.org/src/pkg/container/list/list.go line 138) and list.Remove() creates garbage for the GC.

This doesn't seem like it saves much GC work.

A while back I wrote a "StackSlice" implementation to recycle memory which uses a statically allocated slice and pushes pointers to objects onto the stack. This is nice because pushes and pops don't involve any memory allocations.

1 comments

The elements of the doubly-linked list are slices. A slice can be thought of as a reference to a backing array. The only things being created or collected by the GC in this case are the Element bookkeeping structures (and possibly some slice headers) which contains the the slice.

The memory that is being recycled in the example is storage region of the slice, the size of which is arbitrary. It seems that by default they preallocate a 100-element byte array.

Right, I agree with you. Its not that the strategy won't save any memory. But it won't save any memory allocations because the list still makes them. The number of allocations can put pressure on a garbage collector just as much as large allocations. Maybe even more with fragmentation and the like.

In C you explicitly choose stack vs heap allocation. In go, the runtime does this for you. I had a couple of situations where, after profiling, most of my CPU time was going to heap memory allocations. Using the strategy on slide 13 probably would have helped some to reduce the size of the allocation, but in my case only by a few bytes. Using a fixed-size slice that held references to objects made a big different in performance.

In regards to slide 13 it just seems funny to "recycle" memory by forcing a whole new allocate/deallocate cycle.