4 ms·
The other downside is fragmentation(which is also why even embedded native tends to be static/up-front allocation based).
by vvanders 9y ago
The other downside is fragmentation(which is also why even embedded native tends to be static/up-front allocation based).
- vidarh 9y agoThat's true, and certainly if you can avoid dynamic allocations, do. But you can actually get "halfway" to a partially compacting gc very easily too if memory use is a bigger concern than performance and you want to avoid fragmentation: Set a (small) fixed size for all objects. It can be anything from a single pointer to any data that will be present in all objects. E.g. you might have class pointers and flags and a fixed number of bytes for auxiliary data. If any class needs more instance data, you make a pointer in that primary layout point to space in a secondary heap. Now compacting the secondary heap is easy: Just copy into new buffers and deallocate the old and update a single pointer per object. You can do that by a single pass through all allocated objects, or you can do something more complex. Compacting the primary heap is still messy (you'd need to identify all sites pointing to each object), but if you chose a small size for the primary objects there's less reason to do so, as while it is still possible to create pathological allocation patterns, unless the application reaches a high water mark and then frees a huge number of objects that it then never need again, any empty space left behind can always be perfectly filled by new primary object allocations, and hopefully each such object is fairly small. If you want to, though, you can also compact auxiliary data (the "secondary heap") into holes in the primary heap when there's a good enough fit. E.g. on top of the steps I outlined: For each object, if there's an auxiliary data pointer, check if there's a suitable hole (keep lists by "hole size" for example) in the primary heap. If so, move there. If not, copy to end of new secondary heap. Update source pointer.