我想调整由MS窗口的VirtualAlloc分配的内存区域的大小.查看VirtualFree文档,可以仅部分地解除区域,但不可能部分释放它.也就是说,可以释放部分物理内存,但不能释放虚拟内存的一部分.
我知道在这种情况下可能有必要重新分配该区域.但是,复制整个区域的效率会相当低.有没有办法要求Windows分配一个不同大小的新区域,指向相同的内存?
解决方法
正如您所提到的,似乎无法部分释放一系列保留页面,因为
VirtualFree()
documentation声明:
If the dwFreeType parameter is MEM_RELEASE,[lpAddress] must be the base address returned by the 07001 function when the region of pages [was] reserved.
以及:
If the dwFreeType parameter is MEM_RELEASE,[dwSize] must be 0 (zero).
VirtualFree()本身是内核函数NtFreeVirtualMemory()的瘦包装器. Its documentation page(与ZwFreeVirtualMemory()相同)也有此措辞.
一种可能的解决方法是将单个大型预留与多个较小的预留分开.例如,假设您通常一次保留8 MiB的虚拟地址空间.您可以尝试在32个连续的256 KiB预留中保留范围.第一个256 KiB预留将包含一个32位无符号位字段,如果获得第i个256 KiB预留,则设置第i位:
#define NOMINMAX #include <windows.h> #include <assert.h> #include <stddef.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> #define RESERVATION_SIZE (256*1024) typedef struct st_first_reservation { size_t reservation_size; uint32_t rfield; char premaining[0]; } st_first_reservation; int main() { SYSTEM_INFO sys_info = { 0 }; GetSystemInfo(&sys_info); assert((RESERVATION_SIZE % sys_info.dwPageSize) == 0); void *vp = VirtualAlloc(NULL,32*RESERVATION_SIZE,MEM_RESERVE,PAGE_NOACCESS); if (VirtualFree(vp,MEM_RELEASE) == 0) { fprintf(stderr,"Error: VirtualFree() Failed.\n"); return EXIT_FAILURE; } st_first_reservation *pfirst_reservation = (st_first_reservation *) VirtualAlloc(vp,RESERVATION_SIZE,MEM_RESERVE | MEM_COMMIT,PAGE_READWRITE); if (pfirst_reservation == NULL) { pfirst_reservation = (st_first_reservation *) VirtualAlloc(NULL,PAGE_READWRITE); if (pfirst_reservation == NULL) { fprintf(stderr,"Error: VirtualAlloc() Failed.\n"); return EXIT_FAILURE; } } fprintf(stderr,"pfirst_reservation = 0x%p\n",(void *) pfirst_reservation); pfirst_reservation->reservation_size = RESERVATION_SIZE; pfirst_reservation->rfield = 1LU; char *p = (char *) pfirst_reservation; unsigned i = 1; for (; i < 32; ++i) { vp = VirtualAlloc(p += RESERVATION_SIZE,PAGE_NOACCESS); if (vp != NULL) { assert(((void *) vp) == p); pfirst_reservation->rfield |= 1LU << i; fprintf(stderr,"Obtained reservation #%u\n",i + 1); } else { fprintf(stderr,"Failed to obtain reservation #%u\n",i + 1); } } fprintf(stderr,"pfirst_reservation->rfield = 0x%08x\n",pfirst_reservation->rfield); return EXIT_SUCCESS; }
样本输出:
pfirst_reservation = 0x009A0000 Obtained reservation #2 Obtained reservation #3 Obtained reservation #4 Obtained reservation #5 Obtained reservation #6 Obtained reservation #7 Obtained reservation #8 Obtained reservation #9 Obtained reservation #10 Obtained reservation #11 Obtained reservation #12 Obtained reservation #13 Obtained reservation #14 Obtained reservation #15 Obtained reservation #16 Obtained reservation #17 Obtained reservation #18 Obtained reservation #19 Obtained reservation #20 Obtained reservation #21 Obtained reservation #22 Obtained reservation #23 Obtained reservation #24 Obtained reservation #25 Obtained reservation #26 Obtained reservation #27 Obtained reservation #28 Obtained reservation #29 Obtained reservation #30 Obtained reservation #31 Obtained reservation #32 pfirst_reservation->rfield = 0xffffffff
编辑:我发现最好一次“预先保留”32个256 KiB范围,免费,然后尝试尽可能多地重新预留.
在多线程环境中,代码可能会回退到第一个预留的“任何地方”分配.也许最好尝试在保留然后释放的32 * RESERVATION_SIZE字节范围内保留RESERVATION_SIZE字节五次左右,最后回到“任何地方”分配.