HeapReAlloc behavior for different heaps

AndreyT 0 Reputation points
2024-03-14T21:59:10.3233333+00:00

The behavior below is tested in Visual Studio 2022.

Calling HeapReAlloc on a private heap without changing the block size results in a no-op (as one would expect)

HANDLE heap = HeapCreate(0, 0, 65536);
void *p = HeapAlloc(heap, 0, 10);
printf("%p\n", p);
p = HeapReAlloc(heap, 0, p, 10);
printf("%p\n", p);
...

The above printf calls output the same pointer value.

However, if instead of private heap I use the default process heap

HANDLE heap = GetProcessHeap();
void *p = HeapAlloc(heap, 0, 10);
printf("%p\n", p);
p = HeapReAlloc(heap, 0, p, 10);
printf("%p\n", p);
...

then the pointer value will change with every HeapReAlloc call.

Another side-effect of apparently the same behavioral peculiarity is that all HeapReAlloc calls to default process heap with HEAP_REALLOC_IN_PLACE_ONLY flag and the same (or smaller) size tend to fail without a good reason. My experiment shows that in order to for such HeapReAlloc call for size 10 to succeed the initial block size must be around 160-175 (the exact boundary seems to float):

HANDLE heap = GetProcessHeap();

void *p = HeapAlloc(heap, 0, 200);
p = HeapReAlloc(heap, HEAP_REALLOC_IN_PLACE_ONLY, p, 10); // usually succeeds

p = HeapAlloc(heap, 0, 100);
p = HeapReAlloc(heap, HEAP_REALLOC_IN_PLACE_ONLY, p, 10); // usually fails

Why does the default process heap behave like that? What specific property of default process heap makes it behave this way? How can I create a private heap that mimics the behavior of the default process heap wrt same-size HeapReAlloc?

Windows API - Win32
Windows API - Win32
A core set of Windows application programming interfaces (APIs) for desktop and server applications. Previously known as Win32 API.
2,405 questions
C++
C++
A high-level, general-purpose programming language, created as an extension of the C programming language, that has object-oriented, generic, and functional features in addition to facilities for low-level memory manipulation.
3,503 questions
{count} votes

1 answer

Sort by: Most helpful
  1. Tong Xu - MSFT 611 Reputation points Microsoft Vendor
    2024-03-19T03:14:31.96+00:00

    Hi, AndreyT
    Welcome to Microsoft Q&A!

    It is recommended to read this article. Your question and requirement can be explained and met in here: Managing Heap Memory.

    Why does the default process heap behave like that? What specific property of default process heap makes it behave this way?

    In its simplest form, the default heap spans a range of addresses. Some ranges are reserved, while others are committed and have pages of memory associated with them. In this case the addresses are contiguous, and they all originated from the same base allocation address. In some cases the default heap needs to allocate more memory than is available in its current reserved address space. For these cases the heap can either fail the call that requests the memory, or reserve an additional address range elsewhere in the process.

    When the default heap needs more memory than is currently available, it reserves another 1-MB address range in the process. It also initially commits as much memory as it needs from this reserved address range to satisfy the allocation request. The default heap manager is then responsible for managing this new memory region as well as the original heap space. If necessary, it will repeat this throughout the application until the process runs out of memory and address space.

    How can I create a private heap that mimics the behavior of the default process heap wrt same-size HeapReAlloc?

    No, you can't. It is by designed is important to note that although heap memory is not movable as in global and local memory, it may be moved during the HeapReAlloc function. This function returns a pointer to the resized chunk of memory, which may or may not be at the same location as initially indicated by the pointer passed to the function. This is the only time memory can be moved in dynamic heaps, and the only chunk of memory affected is the one identified by lpMem in the function. You can also override this behavior by specifying the HEAP_REALLOC_IN_PLACE_ONLY flag. With this flag, if there is not enough room to reallocate the memory in place, the function returns with failure status rather than move the memory.

    Thank you.


    If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".

    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    0 comments No comments