Windows Programming/Memory Subsystem
C programmers will undoubtedly be familiar with the stdlib memory allocation functions, malloc, realloc, calloc, etc. These functions are based off a number of other functions in the Win32 API that deal with memory segments.
When talking about the memory subsystem, there are 4 distinct types of memory that Windows manages, and each type of memory has a number of different functions to allocate and free that memory.
- Virtual Memory
- The Virtual Memory subsystem allocates and manages memory by pages. This means that memory can only be allocated in blocks of 4 Kbytes (or larger, depending on processor architecture) at a time. This is a fantastically large amount of memory for most applications, and using the virtual memory functions in most programs is overkill. However, some programs do need use of entire pages for storage, so the Virtual Memory subsystem can be used for that.
- Heap Memory
- The heap is an area of memory that usually takes up a whole page, or a fraction of a page. Each process is allocated a heap immediately by windows, called the process heap. The stdlib functions such as malloc will allocate memory from this memory region. The heap can be divided up into small memory segments, for use with variables and dynamic storage.
- Global Memory
- Windows maintains at least 1 page of memory for use as general-purpose global memory. This memory can be read or written by any process running on the computer, using the global memory functions. Data in the global memory space can be shared among various programs, and items sent to the windows clipboard are generally stored in global memory (so it can be "pasted" into any program). Global memory is limited, so it should not be used without a specific need.
- Local memory has similarities to both global memory and heap memory. It is local to the process, but the memory is managed by the Windows memory manager, and not by the program. We will discuss this later.
Virtual Memory Subsystem
The virtual memory functions, as explained above, allocate memory in terms of pages. Pages are generally 4 Kbytes of memory, so most applications won't need to allocate an entire page (much less more then 1 page). The Virtual memory system is essentially the primitive function base that the other memory functions utilize to perform their tasks. For instance, the heap is comprised of 1 or more pages, and the heap functions will allocate pages using the virtual memory system when needed.
When virtual memory blocks are allocated, they are not actually being utilized, they are simply reserved by the system for future use. Other functions need to be used to segment the virtual memory pages into useful segments. Since virtual memory is allocated by pages, a number of special paging features can be used on virtual memory that can not be used on other types of memory. For instance, pages can be locked (to prevent read/write access), or they can be protected from any particular access mode (read, write, execute).
That said, there are a number of functions in the virtual memory subsystem that can be used:
Each program is provided with a default process heap, but a process may optionally allocate any number of additional heaps, if more storage is needed. The heap functions will manage their virtual memory usage automatically, and therefore heaps can be set to grow if they are being filled up with data. If a heap is allowed to grow automatically, the heap functions will automatically allocate additional pages as needed. On the x86 architecture the heap grows in size towards higher memory addresses.
To use heap memory, a heap must first be allocated (or a handle must be obtained to the default heap). Once you have obtained a handle to a heap, you can pass that handle to the memory allocation functions, to allocate memory from that particular heap.
The stdlib memory functions (malloc, realloc, calloc, free) are all used very similarly to the heap functions, so programmers familiar with the stdlib functions may be able to figure out what many of the heap functions are doing, by examining their names:
- Allocates a heap, and returns a handle to that heap. All the other heap functions will use this handle to uniquely identify the particular heap that you are accessing. By maintaining multiple handles, your program may interface with multiple separate heaps.
- This function closes a heap handle, and deallocates the heap memory so that other processes can use it.
- This function returns a handle to the default process heap. Each program gets a default heap when it is loaded, and in most applications this should be enough space to store data items.
- Similar to the STDLIB "malloc" function, HeapAlloc allocates storage space on the heap, and returns a pointer to that space.
- Similar to the STDLIB "realloc" function, HeapReAlloc reallocates the storage space of a variable to be a different size.
- Frees a memory object on the heap. Attempts to use the same pointer to access memory after it has been freed will cause an error.
Windows maintains a certain amount of global heap memory. This memory is limited compared to regular process heaps, and should not be accessed unless global memory is specially required.
When data has been written to the global memory, you don't get a pointer to that data, but instead you get a handle for that data. Once you give your data to the global memory manager, the system is in charge of it. Remember, a handle is not a pointer, and should never be used as one. The system will manage the memory in the global memory section, moving it between pages, and defragmenting it, et cetera. Data doesn't reside within a single segment
Local memory, in this sense, is not the kind of storage that programs utilize internally, on the stack and otherwise. Instead, Windows manages a special section of memory that it dubs to be "Local Memory", and it provides a number of functions to allocate and manage this special memory. Local memory is similar to global memory in the sense that data is written to the local location, and the system returns a handle to that data. The system will manage the data, just like in global memory. The local functions are named very similarly to the global memory functions. However, the global memory and local memory functions should never be mixed. For instance, a global memory handle should never be closed with the LocalFree function.