You create a discardable memory block by combining the GMEM_DISCARDABLE and GMEM_MOVEABLE options when allocating the block. The resulting block will be moved as necessary to make room for other allocation requests; or if there is not enough memory to satisfy the request, the block may be discarded. The following example allocates a discardable block from global memory:
hMem = GlobalAlloc(GMEM_MOVEABLE | GMEM_DISCARDABLE, 4096L);
When Windows discards a memory block, it empties the block by reallocating it, with zero bytes given as the new size. The contents of the block are lost, but the memory handle to this block remains valid. Any attempt to lock the handle and access the block will fail, however.
Windows determines which memory blocks to discard by using a least-recently-used (LRU) algorithm. It continues to discard memory blocks until there is enough memory to satisfy an allocation request. In general, if you have not accessed a discardable block in some time, it is a candidate for discarding. A locked block cannot be discarded.
You can discard your own memory blocks by using the GlobalDiscard function. This function empties the block but preserves the memory handle. You can also discard other applications' memory blocks by using the GlobalCompact function. This function moves and discards memory blocks until the specified or largest possible amount of memory is available. One way to discard all discardable blocks is to supply –1 as the argument. This is a request for every byte of memory. Although the request will fail, it will discard all discardable blocks and leave the largest possible block of free memory.
Since a discarded memory block's handle remains valid, you can still retrieve information about the block by using the GlobalFlags function. This is useful for verifying that the block has actually been discarded. GlobalFlags sets the GMEM_DISCARDED bit in its return value when the specified memory block has been discarded. Therefore, if you attempt to lock a discardable block and the lock fails, you can check the block's status by using GlobalFlags.
Once a discardable block has been discarded, its contents are lost. If you wish to use the block again, you need to reallocate it to its appropriate size and fill it with the data it previously contained. You can reallocate it by using the GlobalReAlloc function. The following example checks the block's status, then fills it with data if it has been discarded:
lpMem = GlobalLock(hMem);
if (lpMem == (LPSTR) NULL) {
if (GlobalFlags(hMem) & GMEM_DISCARDED) {
hMem = GlobalReAlloc(hMem, 4096L,
GMEM_MOVEABLE | GMEM_DISCARDABLE);
lpMem = GlobalLock(hMem);
/* More program lines */
/* Fill with data */
GlobalUnlock(hMem);
}
}
You can make a discardable object nondiscardable (or vice versa) by using the GlobalReAlloc function and the GMEM_MODIFY flag. The following example changes a movable block, identified by the hMem memory handle, to a movable, discardable block:
hMem = GlobalReAlloc(hMem, 0, GMEM_MODIFY | GMEM_DISCARDABLE);
The following example changes a discardable block to a nondiscardable block:
hMem = GlobalReAlloc(hMem, 0, GMEM_MODIFY);