In Automatic Pool Allocation, each pool created by the program at run-time is essentially a distinct
heap, managed internally using some allocation algorithm. We can use the remapping approach
described above within each pool created by the program at run-time. The key benefit is that, at a
pool_destroy, we can release all (shadow and canonical) virtual memory pages of the pool to be
reused by future allocations. Note that physical pages will continue to be reused just as in the
original program, i.e., the physical memory consumption remains the same as in the original program
(except for minor differences potentially caused by using the pool allocator on top of the original heap).
The only significant change in the Allocation and Deallocation operations described above is for reusing
virtual pages. This is slightly tricky because we need to reuse virtual pages that might have been
aliased with other virtual pages previously. One simple solution would be to use the unmap system call
to release previous virtual-to-physical mappings for all pages in a pool after a pool destroy. unmap
would work for both canonical and shadow pages because these are obtained from the Operating System (OS)
via mmap and mremap respectively. Canonical pages are obtained in contiguous blocks from the underlying
system (via mmap) and the blocks can be unmapped efficiently. The shadow pages, however, are potentially
scattered around in the heap, and in the worst case may require a separate unmap operation for every
individual object allocated from the pool (in addition to the earlier mprotect call when the object was
freed). This could be expensive. We avoid the explicit munmap calls by maintaining a free list of
virtual pages shared across pools and adding all pool pages to this free list at a pool_destroy. We
modified the underlying pool allocator to obtain (canonical) pages from this free list, if available. If
this free list is empty, we use mmap to obtain fresh pages from the system as before. For each allocated
object, the shadow page(s) is(are) obtained using mremap as before to ensure a distinct virtual memory page.
A pool_free operation works just like the Deallocation case described previously, and invokes the underlying
pool_ free on the canonical page. A pool_destroy operation simply returns all canonical and shadow pages in
the pool to the shared free list of pages.