Memory Management

This section details the Windows API functions and structures used for managing memory resources within a Windows application. Efficient memory management is crucial for application performance, stability, and resource utilization.

Virtual Memory

Windows employs a virtual memory system that provides each process with its own private virtual address space. This abstraction allows applications to use more memory than is physically available and protects processes from interfering with each other's memory.

  • Address Space: Each process has a 64-bit virtual address space (on 64-bit systems).
  • Pages: The virtual address space is divided into fixed-size units called pages.
  • Memory Mapping: Virtual addresses are mapped to physical memory (RAM) or page file contents by the Memory Manager.

Key Memory Management Concepts and Functions

1. Allocating and Freeing Memory

The primary functions for dynamic memory allocation are:

  • VirtualAlloc: Reserves or commits a region of pages in the virtual address space of the calling process.
  • VirtualAllocEx: Reserves or commits a region of pages in the virtual address space of a specified process.
  • VirtualFree: Releases or decommits a region of pages within the virtual address space of the calling process.
  • HeapAlloc: Allocates a block of memory from a process's heap.
  • HeapFree: Frees a block of memory allocated from a process's heap.

For simple allocations, the C runtime functions like malloc and free are often used, which internally call the Windows heap functions.

2. Memory Protection

Memory pages can be protected to control access (read, write, execute). Functions for managing memory protection include:

  • VirtualProtect: Changes the access protection for a region of pages in the virtual address space of the calling process.
  • VirtualProtectEx: Changes the access protection for a region of pages in the virtual address space of a specified process.

Common protection flags include:

  • PAGE_READONLY
  • PAGE_READWRITE
  • PAGE_EXECUTE_READ
  • PAGE_EXECUTE_READWRITE

3. Memory Mapping and Sharing

Windows provides mechanisms to map files into memory and to share memory between processes.

  • File Mapping:
    • CreateFileMapping: Creates or opens a named or unnamed file mapping object.
    • MapViewOfFile: Maps a view of a file mapping into the address space of the calling process.
    • UnmapViewOfFile: Unmaps a mapped view of a file from the process's address space.
  • Shared Memory: File mapping objects can be used to create regions of memory that can be accessed by multiple processes.

4. Memory Status and Information

Functions to query memory usage and status:

  • GlobalMemoryStatusEx: Retrieves current information about the amount of physical memory and commit charge for the computer.
  • VirtualQuery: Retrieves information about a region of pages.

Common Memory Management Tasks

Example: Allocating and Writing to Memory


#include <windows.h>
#include <stdio.h>

int main() {
    LPVOID memoryBlock = NULL;
    SIZE_T blockSize = 1024; // 1 KB

    // Allocate 1 KB of memory with read/write access
    memoryBlock = VirtualAlloc(
        NULL,           // Let the system determine the address
        blockSize,      // Size of the region to allocate
        MEM_COMMIT | MEM_RESERVE, // Commit and reserve pages
        PAGE_READWRITE  // Memory protection flags
    );

    if (memoryBlock == NULL) {
        wprintf(L"VirtualAlloc failed. Error: %lu\n", GetLastError());
        return 1;
    }

    wprintf(L"Memory allocated at: %p\n", memoryBlock);

    // Write data to the allocated memory
    const char* message = "Hello, Windows Memory Management!";
    strncpy((char*)memoryBlock, message, blockSize - 1);
    ((char*)memoryBlock)[blockSize - 1] = '\0'; // Ensure null termination

    wprintf(L"Data written to memory: %s\n", (char*)memoryBlock);

    // Free the allocated memory
    if (VirtualFree(memoryBlock, 0, MEM_RELEASE) == 0) {
        wprintf(L"VirtualFree failed. Error: %lu\n", GetLastError());
        return 1;
    }

    wprintf(L"Memory freed.\n");

    return 0;
}
                

Example: Shared Memory using File Mapping

This example demonstrates creating a shared memory section that can be written to by one process and read from by another (though both processes would need to run this code, with one acting as writer and the other as reader, or use synchronization primitives).


#include <windows.h>
#include <stdio.h>

#define SHARED_MEM_NAME L"MySharedMemory"
#define MEM_SIZE 256

int main() {
    HANDLE hMapFile;
    LPVOID lpMapAddress;
    const char* msgToWrite = "This is shared data!";

    // Create or open a named file mapping object
    hMapFile = CreateFileMapping(
        INVALID_HANDLE_VALUE, // Use the paging file
        NULL,                 // Default security attributes
        PAGE_READWRITE,       // Read/write access
        0,                    // Maximum object size (high-order DWORD)
        MEM_SIZE,             // Maximum object size (low-order DWORD)
        SHARED_MEM_NAME       // Name of the mapping object
    );

    if (hMapFile == NULL) {
        wprintf(L"CreateFileMapping failed. Error: %lu\n", GetLastError());
        return 1;
    }

    // Map the file mapping into the address space
    lpMapAddress = MapViewOfFile(
        hMapFile,             // Handle of the file mapping object
        FILE_MAP_ALL_ACCESS,  // Access mode
        0,                    // Offset (high-order DWORD)
        0,                    // Offset (low-order DWORD)
        MEM_SIZE              // Number of bytes to map
    );

    if (lpMapAddress == NULL) {
        wprintf(L"MapViewOfFile failed. Error: %lu\n", GetLastError());
        CloseHandle(hMapFile);
        return 1;
    }

    wprintf(L"Shared memory mapped at: %p\n", lpMapAddress);

    // Write data to the shared memory
    strncpy((char*)lpMapAddress, msgToWrite, MEM_SIZE - 1);
    ((char*)lpMapAddress)[MEM_SIZE - 1] = '\0'; // Null terminate

    wprintf(L"Data written to shared memory: \"%s\"\n", (char*)lpMapAddress);

    // To read, another process would open the same mapping and use MapViewOfFile.
    // For this example, we'll keep it mapped for demonstration.
    // In a real application, you'd have synchronization logic.

    wprintf(L"Press Enter to unmap and close...\n");
    getchar();

    // Unmap the view
    if (!UnmapViewOfFile(lpMapAddress)) {
        wprintf(L"UnmapViewOfFile failed. Error: %lu\n", GetLastError());
    }

    // Close the file mapping handle
    CloseHandle(hMapFile);

    return 0;
}
                

API Reference Table

Function Description Category
VirtualAlloc Reserves or commits a region of pages in the virtual address space. Allocation
VirtualFree Releases or decommits a region of pages. Deallocation
VirtualProtect Changes memory protection for a region of pages. Protection
CreateFileMapping Creates or opens a named or unnamed file mapping object. File Mapping
MapViewOfFile Maps a view of a file mapping into the address space. File Mapping
UnmapViewOfFile Unmaps a mapped view of a file. File Mapping
HeapAlloc Allocates memory from the process heap. Heap Allocation
HeapFree Frees memory from the process heap. Heap Deallocation
GlobalMemoryStatusEx Retrieves information about system memory. Status