c++ - When I reserve memory with VirtualAlloc() and MEM_RESERVE, shouldn't I be able to grow my allocation on a 64K boundary? -


first of all, know how virtualalloc() works: when reserve blocks of memory, addresses aligned 64k boundaries, (a value can obtained getsysteminfo()), when commit pages, them on page size boundary, 4k.

the thing can't get, why if call virtualalloc() mem_reserve flag (so i'm reserving pages) , specify size, let's 4096, won't able grow further region 64k?

what i'm saying is: when commit pages can use memory 4k because windows alignes these commits page size (of course, i'm commiting pages!), when i'm reserving regions of memory, shouldn't windows align size of region pass virtualalloc() 64k? "wasted" 15 pages go?

so if reserve 4096 bytes, shouldn't able commit more pages until 65536 bytes? doesn't seem so, because if try this, virtualalloc() fails error_invalid_address last error code.

but why? if windows reserve pages on 64k boundaries, , reserve pages on less size, loose pages don't reserve forever? because seems there no way commit them again, or resize region fit 64k boundaries i've missed lower reservation.

so, process' virtual space have holes? avoid this, have reserve memory always on 64k boundaries, giving virtualalloc() 64k-aligned value always when i'm reserving pages?

what when use mem_reserve|mem_commit? shoulnd't pass 64k-aligned sizes there, because of mem_reserve flag?

i include little code example i've tried. can see here, first functions succeeds, because reserve more pages, commits have enough "reserved region" committed, but in case, region <64k, "lost" pages go?

in second case, i've mem_reserve|mem_commit, committing other pages fails error_invalid_address last error code. fair enough, here, why can't commit more pages, @ least on 64k boundary? not waste addresses , create these "holes", should reserve virtual memory on 64k boundaries? if don't follow principle? see a lot of code around calls virtualalloc() mem_commit|mem_reserve flags, not caring 64k align thing. allocating memory in wrong way? thoughts?

#include <stdlib.h> #include <stdio.h> #include <windows.h>  #define page_sz 4096   bool reserve_and_commit() {   memory_basic_information mem_info;     void * mem, * mem2; bool result = true;    mem =     virtualalloc(0, page_sz * 1, mem_reserve | mem_commit, page_readwrite);   if (!mem)   {     result = false;     printf("virtualalloc1: error '%d'\n", (unsigned int)getlasterror());   }   else     printf("virtualalloc1: mem_reserve|mem_commit ok. address: %p\n", mem);    printf("\n-------------------------------------\n\n");    if (!virtualquery(mem, &mem_info, sizeof mem_info))   {     result = false;     printf("virtualquery: error '%d'\n", (unsigned int)getlasterror());   }   else     printf("virtualquery: ok. baseaddress:%p allocationbase:%p allocationprotect:%08x "            "regionsize:%d state:%08x protect:%08x type:%08x\n",            mem_info.baseaddress, mem_info.allocationbase, mem_info.allocationprotect,            (unsigned int)mem_info.regionsize, (unsigned int)mem_info.state,            (unsigned int)mem_info.protect, (unsigned int)mem_info.state);    printf("\n-------------------------------------\n\n");    mem2 =     virtualalloc(mem, page_sz * 2, mem_commit, page_readwrite);   if (!mem2)   {     result = false;     printf("virtualalloc2: error '%d'\n", (unsigned int)getlasterror());   }   else     printf("virtualalloc2: mem_commit ok. address: %p\n", mem2);    printf("\n-------------------------------------\n\n");    if (!virtualfree(mem, 0, mem_release))   {     result = false;     printf("virtualfree: error '%d'\n", (unsigned int)getlasterror());   }   else     printf("virtualfree: ok.\n");    return result; }   bool first_reserve_and_then_commit() {   memory_basic_information mem_info;   void * mem_reserved, * mem_committed;   bool result = true;    mem_reserved =     virtualalloc(0, page_sz * 8, mem_reserve, page_readwrite);   if (!mem_reserved)   {     result = false;     printf("virtualalloc1: error '%d'\n", (unsigned int)getlasterror());   }   else     printf("virtualalloc1: mem_reserve ok. address: %p\n", mem_reserved);    printf("\n-------------------------------------\n\n");    if (!virtualquery(mem_reserved, &mem_info, sizeof mem_info))   {     result = false;     printf("virtualquery1: error '%d'\n", (unsigned int)getlasterror());   }   else    printf("virtualquery1: ok. baseaddress:%p allocationbase:%p allocationprotect:%08x "            "regionsize:%d state:%08x protect:%08x type:%08x\n",            mem_info.baseaddress, mem_info.allocationbase, mem_info.allocationprotect,            (unsigned int)mem_info.regionsize, (unsigned int)mem_info.state,            (unsigned int)mem_info.protect, (unsigned int)mem_info.state);    printf("\n-------------------------------------\n\n");    mem_committed =     virtualalloc(mem_reserved, page_sz * 1, mem_commit, page_readwrite);   if (!mem_committed)   {     result = false;     printf("virtualalloc2: error '%d'\n", (unsigned int)getlasterror());   }   else     printf("virtualalloc2: mem_commit ok. address: %p\n", mem_committed);    printf("\n-------------------------------------\n\n");    if (!virtualquery(mem_committed, &mem_info, sizeof mem_info))   {     result = false;     printf("virtualquery2: error '%d'\n", (unsigned int)getlasterror());   }   else     printf("virtualquery2: ok. baseaddress:%p allocationbase:%p allocationprotect:%08x "            "regionsize:%ul state:%08x protect:%08x type:%08x\n",            mem_info.baseaddress, mem_info.allocationbase, mem_info.allocationprotect,            (unsigned int)mem_info.regionsize, (unsigned int)mem_info.state,            (unsigned int)mem_info.protect, (unsigned int)mem_info.state);    printf("\n-------------------------------------\n\n");    mem_committed =     virtualalloc(mem_committed, page_sz * 8, mem_commit, page_readwrite);   if (!mem_committed)   {     result = false;     printf("virtualalloc3: error '%d'\n", (unsigned int)getlasterror());   }   else     printf("virtualalloc3: mem_commit ok. address: %p\n", mem_committed);    printf("\n-------------------------------------\n\n");    if (!virtualfree(mem_reserved, 0, mem_release))   {     result = false;     printf("virtualfree: error '%d'\n", (unsigned int)getlasterror());   }   else     printf("virtualfree: ok.\n");    return result; }    int main() {   first_reserve_and_then_commit();   reserve_and_commit();   return 0; } 

as demonstrated program, virtual pages aren't automatically reserved when allocated. when reserve single page virtualalloc entire 64k block of pages allocated, single page reserved. can commit pages have been reserved, when program tries commit allocated unreserved pages call virtualalloc fails.

as why works way, simple answer way it's documented work. no in documentation state virtualalloc ever reserve more pages ask to. don't have insight on why microsoft chose implement way, seems meets principle of least astonishment. in particular means less programs break if decide change allocation granularity size since it's hidden implementation detail. (however, @ point don't think it's possible microsoft change this.) might reduce memory needed keeping track of reserved pages.

as what's best practice when using virtualalloc recommendation should used allocate memory in sizes greater 64k , ideally bigger. since no physical memory lost when allocating regions smaller 64k, virtual address space, many programs doesn't matter. debugging aid, once used custom version of malloc in program used virtualalloc allocations, of smaller 4k, let alone 64k.


Comments

Popular posts from this blog

javascript - Karma not able to start PhantomJS on Windows - Error: spawn UNKNOWN -

c# - Display ASPX Popup control in RowDeleteing Event (ASPX Gridview) -

Nuget pack csproj using nuspec -