如何调整VirtualAlloc分配的区域的大小?

前端之家收集整理的这篇文章主要介绍了如何调整VirtualAlloc分配的区域的大小?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我想调整由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字节五次左右,最后回到“任何地方”分配.

猜你在找的C&C++相关文章