Before creating a heap, you must first allocate a block of memory large enough to hold the heap. The block must be large enough to satisfy all the memory requests your program will make of it, and also be able to hold internal information required to manage the heap. Once the block is fully allocated, further allocation requests to the heap will fail.
The internal information requires _HEAP_MIN_SIZE bytes (_HEAP_MIN_SIZE is defined in <umalloc.h>). You cannot create a heap smaller than this. Add the amount of memory your program requires to this value to determine the size of the block you need to get. Also make sure the block is the correct type (regular or shared) for the heap you are creating.
After you have allocated a block of memory, create the heap with _ucreate.
For example:
Heap_t fixedHeap; /* this is the "heap handle" */ /* get memory for internal info plus 5000 bytes for the heap */ static char block[_HEAP_MIN_SIZE + 5000]; fixedHeap = _ucreate(block, (_HEAP_MIN_SIZE+5000), /* block to use */ !_BLOCK_CLEAN, /* memory is not set to 0 */ _HEAP_REGULAR, /* regular memory */ NULL, NULL); /* we'll explain this later */
The !_BLOCK_CLEAN parameter indicates that the memory in the block has not been initialized to 0. If it were set to 0 (for example, by memset), you would specify _BLOCK_CLEAN. The calloc and _ucalloc functions use this information to improve their efficiency; if the memory is already initialized to 0, they don't need to initialize it.
The fourth parameter indicates what type of memory the heap contains: regular (_HEAP_REGULAR) or shared (_HEAP_SHARED). The different memory types are described in Types of Memory.
For a fixed-size heap, the last two parameters are always NULL.
Using Your Heap
Once you have created your heap, you can open it for use
by calling _uopen:
_uopen(fixedHeap);
This opens the heap for that particular process; if the heap is shared, each process that uses the heap needs its own call to _uopen.
You can then allocate and free from your own heap just as you would from the default heap. To allocate memory, use _ucalloc or _umalloc. These functions work just like calloc and malloc, except you specify the heap to use as well as the size of block that you want. For example, to allocate 1000 bytes from fixedHeap:
void *up; up = _umalloc(fixedHeap, 1000);
To reallocate and free memory, use the regular realloc and free functions. Both of these functions always check what heap the memory came from, so you don't need to specify the heap to use. For example, the realloc and free calls in the following code fragment look exactly the same for both the default heap and your heap:
void *p, *up; p = malloc(1000); /* allocate 1000 bytes from default heap */ up = _umalloc(fixedHeap, 1000); /* allocate 1000 from fixedHeap */ realloc(p, 2000); /* reallocate from default heap */ realloc(up, 100); /* reallocate from fixedHeap */ free(p); /* free memory back to default heap */ free(up); /* free memory back to fixedHeap */
For any object, you can find out what heap it was allocated from by calling _mheap. You can also get information about the heap itself by calling _ustats, which tells you:
When you call any heap function, make sure the heap you specify is valid. If the heap is not valid, the behavior of the heap functions is undefined.
Adding to a Fixed-Size Heap
Although you created the heap with a fixed size, you can
add blocks of memory to it with _uaddmem. This can be
useful if you have a large amount of memory that is allocated
conditionally. Like the starting block, you must first allocate
memory for a block of memory. This block will be added to the
current heap, so make sure the block you add is the same type of
memory as the heap you are adding it to.
For example, to add 64K to fixedHeap:
static char newblock[65536]; _uaddmem(fixedHeap, /* heap to add to */ newblock, 65536, /* block to add */ _BLOCK_CLEAN); /* sets memory to 0 */
Using _uaddmem is the only way to increase the size of a fixed heap.
Note: For every block of memory you add, a small number of bytes from it are used to store internal information. To reduce the total amount of overhead, it is better to add a few large blocks of memory than many small blocks.
Destroying Your Heap
When you have finished using the heap, close it with _uclose.
Once you have closed the heap in a process, that process can no
longer allocate from or return memory to that heap. If other
processes share the heap, they can still use it until you close
it in each of them. Performing operations on a heap after you've
closed it causes undefined behavior.
To finally destroy the heap, call _udestroy. If blocks of memory are still allocated somewhere, you can force the destruction. Destroying a heap removes it entirely even if it was shared by other processes. Again, performing operations on a heap after you've destroyed it causes undefined behavior.
After you destroy your fixed-size heap, it is up to you to return the memory for the heap (the initial block of memory you supplied to _ucreate and any other blocks added by _uaddmem) to the system.
Memory Management Functions
Managing Memory with Multiple
Memory Heaps
Types of Memory
Debugging Memory Heaps
Creating and Using an Expandable Heap
Debugging Problems with Heap Memory
Changing the Default Heap Used in a
Program
Example of Creating and Using a User Heap
Example of Creating and Using a
Shared-Memory User Heap