C++ VirtualAlloc的内存使用率高于预期;什么';发生什么事了?

C++ VirtualAlloc的内存使用率高于预期;什么';发生什么事了?,c++,winapi,64-bit,virtual-memory,virtualalloc,C++,Winapi,64 Bit,Virtual Memory,Virtualalloc,重要信息:在此处投入太多时间之前,请向下滚动至“最终更新”。事实证明,主要的教训是要当心unittest套件中其他测试的副作用,并且在得出结论之前总是孤立地复制东西 表面上看,以下64位代码使用(总共4G字节)分配(和访问)一个兆4k页面: const size\u t N=4;//用这么多千兆字节进行测试 const size\u t pagesize4k=4096; 常量大小\u t N页面=(N 您不会得到4096字节,它将被四舍五入到允许的最小分配。这是SYSTEM_INFO.dwAl

重要信息:在此处投入太多时间之前,请向下滚动至“最终更新”。事实证明,主要的教训是要当心unittest套件中其他测试的副作用,并且在得出结论之前总是孤立地复制东西


表面上看,以下64位代码使用(总共4G字节)分配(和访问)一个兆4k页面:

const size\u t N=4;//用这么多千兆字节进行测试
const size\u t pagesize4k=4096;
常量大小\u t N页面=(N
您不会得到4096字节,它将被四舍五入到允许的最小分配。这是SYSTEM_INFO.dwAllocationGranularity,它已经是64KB了很长一段时间。这是一个非常基本的地址空间碎片计数器度量


因此,您分配的方式比您想象的要多。

事实证明,观察到的问题完全是由于测试套件中的前一个单元测试使用了TBB的“可伸缩分配器”分配/取消分配几GB的数据。似乎可伸缩分配器实际上会将这些分配保留在自己的池中,而不是将其返回到系统中(参见或)。当我单独运行测试并在测试后有足够的睡眠时间来观察任务管理器中的完成时工作集时,这一点变得很明显。

VirtualAlloc将实际保留并提交64KB粒度边界,或保留64KB,但提交页面(4KB)边界和页面大小块?嗯,这是一个有趣的信息;我的解释更像是marcin_i的解释。我有点惊讶,如果是这样的话,我不仅会崩溃和烧坏,或者看到工作集膨胀到64GB…但可能事实上,我只在每个alloc中触摸第一个页面救了我。很容易测试…我也应该是一个也可以在每次分配时点击*(reinterpret_cast(pages[i])+4096)=1而不崩溃吗?不幸的是,我要到下周才能再次访问Windows计算机…是的,将VM映射到RAM仍然是基于页的,粒度为4096字节。只需将提交大小与工作集进行比较,以查看差异。(好的,我实际上启动了一个Windows EC2实例来进一步使用它)。那么“粒度”地址范围内的其他60K页的状态是什么?它们显然也没有提交,因为访问+4096字节偏移量会产生访问冲突。它们是保留的,但没有提交吗?尝试一下(从未故意弄错),它们看起来只是不可用。无法将它们提交或重新分配。
malloc
使用
HeapAlloc
,将内存管理委托给堆管理器。堆管理器使用
VirtualAlloc
实现,但会跟踪未使用的内存,以便它不会被浪费。有关
Virtu的更多信息,请参阅alAlloc
const size_t N=4;  // Tests with this many Gigabytes
const size_t pagesize4k=4096;
const size_t npages=(N<<30)/pagesize4k;

BOOST_AUTO_TEST_CASE(test_VirtualAlloc) {

  std::vector<void*> pages(npages,0);
  for (size_t i=0;i<pages.size();++i) {
    pages[i]=VirtualAlloc(0,pagesize4k,MEM_RESERVE|MEM_COMMIT,PAGE_READWRITE);
    *reinterpret_cast<char*>(pages[i])=1;
  }

  // Check all allocs succeeded
  BOOST_CHECK(std::find(pages.begin(),pages.end(),nullptr)==pages.end()); 

  // Free what we allocated
  bool trouble=false;
  for (size_t i=0;i<pages.size();++i) {
    const BOOL err=VirtualFree(pages[i],0,MEM_RELEASE);
    if (err==0) trouble=true;
  }
  BOOST_CHECK(!trouble);
}
char*const ptr = reinterpret_cast<char*>(
  VirtualAlloc(0, 4096, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE)
);
ptr[0] = 1;
ptr[4096] = 1;
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>

#include <vector>

int main(int, char**) {

    const size_t N = 4;
    const size_t pagesize4k = 4096;
    const size_t npages = (N << 30) / pagesize4k;

    std::vector<void*> pages(npages, 0);
    for (size_t i = 0; i < pages.size(); ++i) {
        pages[i] = VirtualAlloc(0, pagesize4k, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
        *reinterpret_cast<char*>(pages[i]) = 1;
    }

    Sleep(5000);

    for (size_t i = 0; i < pages.size(); ++i) {
        VirtualFree(pages[i], 0, MEM_RELEASE);
    }

    return 0;
}
   pages[i]=VirtualAlloc(0,pagesize4k,MEM_RESERVE|MEM_COMMIT,PAGE_READWRITE);