我想调整由MS窗口的VirtualAlloc分配的内存区域.查看VirtualFree文档,可以仅部分地解除区域,但不可能部分释放它.也就是说,可以释放部分物理内存,但不能释放虚拟内存的一部分.
我知道在这种情况下可能有必要重新分配该区域.但是,复制整个区域的效率会相当低.有没有办法让windows分配一个不同大小的新区域,指向同一个内存?
正如您所提到的,似乎不可能部分释放一系列保留页面,因为VirtualFree()文档指出:
如果dwFreeType参数是 MEM_RELEASE,则 [ lpAddress ] 必须是当页面区域被保留时VirtualAlloc函数返回的基地址。
也:
如果dwFreeType参数是 MEM_RELEASE,则 [ dwSize ] 必须为 0(零)。
VirtualFree()本身就是内核函数的一个瘦包装器NtFreeVirtualMemory()。它的文档页面(与 for 相同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, 0, 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, RESERVATION_SIZE, MEM_RESERVE | MEM_COMMIT, 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, RESERVATION_SIZE, MEM_RESERVE, 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;
}
Run Code Online (Sandbox Code Playgroud)
示例输出:
pfirst_reservation = 0x009A0000 获得预订#2 获得预订#3 获得预订#4 获得预订#5 获得预订#6 获得预订#7 获得预订#8 获得预订#9 获得预订#10 获得预订#11 获得预订#12 获得预订#13 获得预订#14 获得预订#15 获得预订#16 获得预订#17 获得预订#18 获得预订#19 获得预订#20 获得预订#21 获得预订#22 获得预订#23 获得预订#24 获得预订#25 获得预订#26 获得预订#27 获得预订#28 获得预订#29 获得预订#30 获得预订#31 获得预订#32 pfirst_reservation->rfield = 0xffffffff
编辑:我发现最好一次“预先保留”32 个 256 KiB 范围,免费,然后尝试重新保留尽可能多的范围。
我更新了上面的代码和示例输出。
在多线程环境中,代码可能会回退到第一个预留的“任意位置”分配。也许尝试RESERVATION_SIZE在保留然后释放的32*RESERVATION_SIZE字节范围内保留字节五次左右是一个好主意,最终回退到“任何地方”分配。