15.1.2 Using the Local Heap

The local heap contains free memory that may be allocated for private use by the application. The local heap is located in the application's data segment and is therefore accessible only to a specific instance of the application. You can allocate memory from the local heap in sizes of up to 64K and the memory can be fixed, movable, or discardable, as needed.

Windows does not automatically supply a local heap for an application. To request a local heap for your application, use the HEAPSIZE statement in the application's module-definition file. This statement sets the initial size, in bytes, of the local heap. If the local heap is in a fixed data segment, you may allocate up to the specified heap size. If the local heap is in a movable data segment, you may allocate beyond the initial heap size and up to 64K, since Windows will automatically allocate additional space for the local heap until the data segment reaches the 64K maximum. You should note, however, that if Windows allocates additional local memory to satisfy a local allocation, it may move the data segment, invalidating any long pointers to objects in local memory.

The maximum size of any local heap depends on the size of the application's stack, static data, and global data. The local heap shares the data segment with the stack and this data. Since a data segment can be no larger than 64K, an application's local heap can be no larger than 64K minus the size of the application's stack, global data, and static data. The application's stack size is defined by the STACKSIZE statement in the application's module-definition file. The global and static data sizes depend on how many strings and global or static variables are declared in the application. Windows enforces a minimum stack size of 5K, so if the module-definition file specifies a smaller stack size, Windows automatically sets the stack size to 5K.

You can allocate local memory by using the LocalAlloc function. This function allocates a memory object in the application's local heap and returns a handle of the memory. You lock the local memory object by using the LocalLock function. This returns a near address (a 16-bit offset) to the first byte in the memory object. The offset is relative to the beginning of your data segment. In the following example, the LocalAlloc function allocates 256 bytes of movable memory, and the LocalLock function locks it so that the first 256 bytes can be set to the address 0xFF:

HANDLE hMem;
PSTR pMem;
int i;

if ((hMem = LocalAlloc(LMEM_MOVEABLE, 256)) != NULL) {
    if ((pMem = LocalLock(hMem)) != NULL) {
        for (i = 0; i < 256; i++)
            pMem[i] = 0xFF;
        LocalUnlock(hMem);
    }
}

In this example, the application unlocks the memory handle by using the LocalUnlock function immediately after accessing the memory object. Once a movable or discardable memory object is locked, Windows guarantees that the object will remain fixed in memory until it is unlocked. This means the address remains valid as long as the object remains locked, but this also prevents Windows from making the best use of memory if other allocation requests are made. If you want to ensure that you are getting the best performance from your application's local heap, make sure you unlock memory after using it.

The LocalAlloc function returns the value NULL if an allocation request fails. You should always check the return value to ensure that a valid handle exists. If you want to, you can determine how much memory is available in the local heap by using the LocalCompact function. This function returns the number of bytes in the largest contiguous free memory object in the local heap.

You should also check the address returned by the LocalLock function. This function returns NULL if the memory handle was not valid or if the contents of the memory object have been discarded.