如何调整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位:

  1. #define NOMINMAX
  2. #include <windows.h>
  3. #include <assert.h>
  4. #include <stddef.h>
  5. #include <stdint.h>
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8.  
  9. #define RESERVATION_SIZE (256*1024)
  10.  
  11. typedef struct st_first_reservation {
  12. size_t reservation_size;
  13. uint32_t rfield;
  14. char premaining[0];
  15. } st_first_reservation;
  16.  
  17. int main()
  18. {
  19. SYSTEM_INFO sys_info = { 0 };
  20. GetSystemInfo(&sys_info);
  21.  
  22. assert((RESERVATION_SIZE % sys_info.dwPageSize) == 0);
  23.  
  24. void *vp = VirtualAlloc(NULL,32*RESERVATION_SIZE,MEM_RESERVE,PAGE_NOACCESS);
  25. if (VirtualFree(vp,MEM_RELEASE) == 0) {
  26. fprintf(stderr,"Error: VirtualFree() Failed.\n");
  27. return EXIT_FAILURE;
  28. }
  29.  
  30. st_first_reservation *pfirst_reservation = (st_first_reservation *) VirtualAlloc(vp,RESERVATION_SIZE,MEM_RESERVE | MEM_COMMIT,PAGE_READWRITE);
  31. if (pfirst_reservation == NULL) {
  32. pfirst_reservation = (st_first_reservation *) VirtualAlloc(NULL,PAGE_READWRITE);
  33. if (pfirst_reservation == NULL) {
  34. fprintf(stderr,"Error: VirtualAlloc() Failed.\n");
  35. return EXIT_FAILURE;
  36. }
  37. }
  38.  
  39. fprintf(stderr,"pfirst_reservation = 0x%p\n",(void *) pfirst_reservation);
  40.  
  41. pfirst_reservation->reservation_size = RESERVATION_SIZE;
  42. pfirst_reservation->rfield = 1LU;
  43.  
  44. char *p = (char *) pfirst_reservation;
  45. unsigned i = 1;
  46. for (; i < 32; ++i) {
  47. vp = VirtualAlloc(p += RESERVATION_SIZE,PAGE_NOACCESS);
  48. if (vp != NULL) {
  49. assert(((void *) vp) == p);
  50. pfirst_reservation->rfield |= 1LU << i;
  51. fprintf(stderr,"Obtained reservation #%u\n",i + 1);
  52. } else {
  53. fprintf(stderr,"Failed to obtain reservation #%u\n",i + 1);
  54. }
  55. }
  56.  
  57. fprintf(stderr,"pfirst_reservation->rfield = 0x%08x\n",pfirst_reservation->rfield);
  58.  
  59. return EXIT_SUCCESS;
  60. }

样本输出

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

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

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

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

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