Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is VirtualAlloc alignment consistent with size of allocation?

When using the VirtualAlloc API to allocate and commit a region of virtual memory with a power of two size of the page boundary such as:

void* address = VirtualAlloc(0, 0x10000, MEM_COMMIT, PAGE_READWRITE); // Get 64KB

The address seems to always be in 64KB alignment, not just the page boundary, which in my case is 4KB.

The question is: Is this alignment reliable and prescribed, or is it just coincidence? The docs state that it is guaranteed to be on a page boundary, but does not address the behavior I'm seeing. I ask because I'd later like to take an arbitrary pointer (provided by a pool allocator that uses this chunk) and determine which 64KB chunk it belongs to by something similar to:

void* chunk = (void*)((uintptr_t)ptr & 0xFFFF0000);
like image 600
random_acts Avatar asked Dec 15 '22 04:12

random_acts


2 Answers

The documentation for VirtualAlloc describes the behavior for 2 scenarios: 1) Reserving memory and 2) Committing memory:

If the memory is being reserved, the specified address is rounded down to the nearest multiple of the allocation granularity.

If the memory is already reserved and is being committed, the address is rounded down to the next page boundary.

In other words, memory is allocated (reserved) in multiples of the allocation granularity and committed in multiples of a page size. If you are reserving and committing memory in a single step, it will be be aligned at a multiple of the allocation granularity. When committing already reserved memory it will be aligned at a page boundary.

To query a system's page size and allocation granularity, call GetSystemInfo. The SYSTEM_INFO structure's dwPageSize and dwAllocationGranularity will hold the page size and allocation granularity, respectively.

like image 140
IInspectable Avatar answered Feb 23 '23 00:02

IInspectable


This is entirely normal. 64KB is the value of SYSTEM_INFO.dwAllocationGranularity. It is a simple counter-measure against address space fragmentation, 4KB pages are too small. The memory manager will still sub-divide 64KB chunks as needed if you change page protection of individual pages within the chunk.

Use HeapAlloc() to sub-allocate. The heap manager has specific counter-measures against fragmentation.

like image 31
Hans Passant Avatar answered Feb 22 '23 23:02

Hans Passant