gpt4 book ai didi

c - 如何调整 VirtualAlloc 分配的区域?

转载 作者:太空狗 更新时间:2023-10-29 17:11:27 26 4
gpt4 key购买 nike

我想调整由 MS 窗口的 VirtualAlloc 分配的内存区域的大小。查看 VirtualFree 文档,可以只部分取消提交一个区域,但不可能部分释放它。即可以释放部分物理内存,但不能释放部分虚拟内存。

我知道在这种情况下可能需要重新分配区域。但是,复制整个区域会相当低效。有没有办法让 Windows 分配一个不同大小的新区域,指向同一内存?

最佳答案

正如您所提到的,似乎不可能部分释放一系列保留页面,因为 VirtualFree() documentation状态:

If the dwFreeType parameter is MEM_RELEASE, [lpAddress] must be the base address returned by the VirtualAlloc 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 位无符号位字段,如果 ith 获得 256 KiB 保留:

#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;
}

示例输出:

pfirst_reservation = 0x009A0000Obtained reservation #2Obtained reservation #3Obtained reservation #4Obtained reservation #5Obtained reservation #6Obtained reservation #7Obtained reservation #8Obtained reservation #9Obtained reservation #10Obtained reservation #11Obtained reservation #12Obtained reservation #13Obtained reservation #14Obtained reservation #15Obtained reservation #16Obtained reservation #17Obtained reservation #18Obtained reservation #19Obtained reservation #20Obtained reservation #21Obtained reservation #22Obtained reservation #23Obtained reservation #24Obtained reservation #25Obtained reservation #26Obtained reservation #27Obtained reservation #28Obtained reservation #29Obtained reservation #30Obtained reservation #31Obtained reservation #32pfirst_reservation->rfield = 0xffffffff

编辑:我发现最好一次性“预留”32 个 256 KiB 范围,免费,然后尝试重新预留尽可能多的范围可以。

我更新了上面的代码和示例输出。

在多线程环境中,代码可能会回退到第一个保留的“任意位置”分配。尝试在 32*RESERVATION_SIZE 字节的保留然后释放范围内保留 RESERVATION_SIZE 字节五次左右,最后回落到“位置”也许是个好主意任何地方”分配。

关于c - 如何调整 VirtualAlloc 分配的区域?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7504482/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com