Octocontrabass wrote:When you're freeing memory, the stack sometimes needs some of that free memory. When that happens, instead of pushing the freed page onto the stack, allocate that page for the stack.
This only works if there's always enough space for the new stack in the address space. In other words realloc(freestack, x) must always return the same pointer. It is not difficult to achieve, and it is a clever optimization indeed. I was thinking about allocating a totally new stack (when realloc() returns a new pointer), which would require a big continuous region that you don't have as free stack being full means free memory is fragmented. I like your idea, nice!
Thpertic wrote:Now the question is: is the slowing down worth it?
Well, considering that it slows down only if you free a block which cannot be merged, but fastens up all the other mergeable frees, I would say probably yes. But to be sure, you should measure both, because this highly depends on your memory allocation usage characteristics. For example if you allocate more pages and you free them in the same order, then freed records would be merged with existing one, therefore being fast. On the other hand if you free them in random order, then there's a good chance that you can't merge most of them and you need to insert over and over again, therefore it would be slower.
To eliminate the slowdown, you can always make it asynchronous, by using a small circular buffer. There free() adds the freed block in O(1) time, and your kernel reads the record from the queue and merges with the free stack when it has the time (the user process doesn't have to wait for it to finish). In this case it doesn't matter how long an insert takes. It's a bit cheating, but user processes won't notice any performance loss (unless the circular buffer is full, then they have to wait exactly the same amount of time as they would have without the async buffer). The only downside is you'd have to have an independent kernel thread to consume records from the queue, which needs scheduling again.
My advice is, don't care about performance at first. Insert the freed record in a way that the free stack remains always sorted and keeps records merged. If you experience performance issues, then you can replace that with an O(1) algorithm and implement a defragmenter, but not sooner. Imho chances are good that you'll be totally happy with free using
logarithmic search like
this one (of course you won't return NULL ever, but the nearest neighbour because that's the record you have to check for merging with, and that's the exact position where you have to insert if cannot be merged).
Cheers,
bzt