Fine tuning and Advanced features

Memory Source

A heap memory source is used when a heap needs additional memory to be added to the free list to satisfy an allocation request. The heap memory source defaults to the operating system. Use SetMemorySource to change the memory source of the heap.

Allocation granularity

The memory manager allocates memory from its memory source in chunks and then splits this into smaller pieces as necessary to satisfy allocation requests. If an allocation request size is larger than the chunk size then enough memory is allocated from the memory source to satisfy the request. You can control the size of memory chunks, with SetChunkSize.

Why would you want to? Consider this

Assume the operating system allocation size is 16k, and your applications makes numerous requests of 9k. The memory manager will get 16k chunks from the operating system and split out 9k for your request. This leaves 7k chunks in the free list. The next 9k request will need to get another chunk from the operating system and split it. Now you have two 7k chunks in the free list. These chunks can be used for  7k or smaller requests, but what if the 9k chunks dominate. Your application will be wasting memory because there will be an excess of available memory in the free list whose size can never satisfy the dominant request, which in this example is 9k.

A heap has two options to handle allocations larger than the chunk size. This option is controlled via SetChunkSize.

  1. Allocate the memory and add it to the internal heap memory list.
  2. Allocate memory directly from the memory source, and deallocate the memory directly back to the memory source on deallocation. This can help in reducing or eliminating memory block fragmentation in many situations.

Minimum allocation size

The memory manager has a minimum allocation size due to its overhead and operations. You can change the minimum allocation size should you desire. You can never set a minimum smaller than default minimum value. Use SetMinAllocSize to change the minimum allocation size.

Search strategy

The memory manager supports two search strategies to find blocks of memory in the free list to satisfy allocation requests, FirstFit and BestFit. Use SetStrategy to change the strategy for a given heap.

FirstFit will take the first block it finds with a size the same as or bigger than the allocation request. If the block is bigger it will be split into two pieces and the remainder will remain in the free list.

BestFit will find the blocks closest in size to the allocation request. Obviously best fit is slower than first fit, but it does fragment memory less than first fit. Realistically most applications due not make very heavy use of allocation and deallocation repeatedly through program execution so BestFit should not affect performance. The compiler in the development system uses FirstFit for performance reasons and the others use BestFit since no performance penalty is measurable and memory fragmentation will be less, although it is not much of an issue for these applications.

A related item to search strategy is the combine mode.  This is very advanced and should not be touched, unless you fully understand the option. The only real use this has is when SetMinAllocSize, FirstFit and NoCombine are used in combination. With this setup you can get extremely fast allocations under very, very heavy allocation/deallocation sequences. All allocated blocks need to be the same size, or multiples of a base size(including overhead). SetMinAllocSize can help maintain a common block size.

Block split strategy

The memory manager supports two split strategies to break large blocks of memory into smaller blocks in the free list to satisfy allocation requests, SplitTopDown and SplitBottomUp. Use SetSplitStrategy to change the strategy for a given heap. Changing the strategy does have the possibility of increasing application performance if the application data structures become better ordered such that the processor cache hit rate is increased.

SplitTopDown is the default. The performance of memory allocations is faster with this option. When splitting a block of memory the upper part, higher address, is the portion returned by the allocation request.

SplitBottomUp returns the lower part, lower address, when splitting a larger block of memory.

Allocation error call back procedure

The memory manager allows you to specify a call back procedure that is called when an allocation request is not satisfied. The default behavior is dependent on the language you are using, but the call back can return three options

ReturnNIL Returns a  NIL, or null, value.
RaiseExcept Raises and exception
TryAgain Tries to allocate again, presumably after you have deallocated some memory or preformed some other action that the allocation might succeed.

Use SetHeapError to change the default allocation error procedure.

Restricting the maximum heap size

You may want to limit the amount of memory a heap, or application, may allocate from the operating system. Use SetHeapMax to limit the maximum size of a heap.

You can freeze a heap at a given size at any point by using FreezeHeap. Once a heap is frozen all allocations must be satisfied by blocks in the free list since the heap will no longer request additional memory from its memory source. You unfreeze a heap at any point.

Either of the above can be used if you are implementing a cache which you want to use a limited amount of memory. The debugger in the development system uses this method. You will want to use SetHeapMax or FreezeHeap to limit the memory and then install an error call back procedure. This procedure can free some memory in the cache and then return TryAgain to continue the allocation.

This is how the debugger sets up its symbol cache heap

CacheHeap := AllocHeap();
SetChunkSizeEx(64*1024, FALSE, CacheHeap);
AllocateEx(addr, 1*1024, CacheHeap);(*chunk will be allocated*)
FreezeHeapEx(TRUE, CacheHeap);
DeallocateEx(addr, 1*1024, CacheHeap);
SetHeapErrorEx(CacheFreeProc, CacheHeap);

Aligned allocations

The memory manager by default returns memory blocks that are aligned such that data types are naturally aligned. If you require memory aligned on a different boundary use AllocateAligned.

Thread safety

The memory manager is thread safe by default on those systems that support threads. For code that is single threaded, or code designed such that no heap contention can occur the thread safe ability of the memory manager induces some overhead. Each heap can have thread safety disabled or enabled at will. In most all applications memory allocation and deallocation does not constitute enough execution time within the application to ever notice the small overhead of thread safety. Therefore it is best to leave thread safety enabled.