**cdunn2001:** _"Pathological"? If dealloc() fragments a large block, then repeated allocation of large blocks would definitely cause memory use to explode._
I was talking about something that sounded like unused space going up while allocated memory remained constant. That would be a pathological case. If I misunderstood you and the ratio unused/used doesn't go up indefinitely, then it wouldn't be. **cdunn2001:** _One interesting note: When I briefly tried boehm, it complained one or twice early in the program about my large allocations._ That has to do with Boehm being a conservative garbage collector (the Nim GCs scan only the stack conservatively, all other roots and the heap are being scanned precisely) and thus more vulnerable to integers and other non-pointer data being misidentified as pointers. **cdunn2001:** _I still would like to see freelist sizes._ I'm not sure what you mean by that. Large blocks in the allocator (type `BigChunk`) are kept in a single list and are allocated using first-fit. Unless you are also allocating a lot of small objects, the amount of free and used memory should be a reasonable approximation in your use case. **cdunn2001:** _Even on Linux, with the simple example I pasted above, you can verify that the already speedy program becomes even speedier after total allocated memory stabilizes, which indicates to me that allocations from existing freelists are quicker than acquiring memory from the system._ That shouldn't be too surprising. The first time, you pay the overhead for mmap and a lot of page faults as memory is being initialized. Try allocating a large `seq`, for example, then do the same and write zeros into it. It should take considerably less than twice the time. * * * In any event, this is all a bit beside the point (the above is about diagnosing the root causes and doesn't give you a solution). Your problem seems to be that large memory allocations lead to more wasted memory that you can justify. The primary problem appears to be fragmentation, and that's tricky to solve, barring a compacting GC; nothing we are talking about here can automatically fix it. The exact solution will depend on what you need the large memory blocks for. If the allocation patterns are relatively simple to manage, then a possible solution would be to use `mmap()` with explicit allocation and deallocation (virtual memory fragmentation is less of an issue on 64-bit machines, except for the 64k limit on mmap()-ed blocks on Linux). To then avoid manual memory management, these large blocks can be wrapped in GCed handlers with finalizers so that deallocation is handled automatically; however, last I checked, Nim didn't have something akin to .NET's `GC.AddMemoryPressure` to make sure that the GC runs frequently enough. One could track the entire mmap()-ed memory, however, and trigger a full GC when it exceeds a certain amount (relative to total memory occupied).
