gpt4 book ai didi

c++ - VirtualAlloc 的内存使用率高于预期;这是怎么回事?

转载 作者:塔克拉玛干 更新时间:2023-11-03 01:45:19 28 4
gpt4 key购买 nike

重要:在您在这里花费太多时间之前向下滚动到“最终更新”。事实证明,主要的教训是提防单元测试套件中其他测试的副作用,并始终在孤立地重现事物,然后再仓促下结论!


从表面上看,以下 64 位代码使用 VirtualAlloc 分配(和访问)一兆 4k 页面(共4GByte):

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

但是,在执行它时会增加“工作集”reported in Windows Task Manager (并通过“峰值工作集”列中的值“坚持”确认)从基线 ~200,000K(~200MByte)到超过 6,000,000 或 7,000,000K(在 64 位 Windows7 上测试,也在 ESX 虚拟化 64 位服务器 2003 和Server 2008;不幸的是,我没有注意到观察到的各种数字发生在哪些系统上)。

同一 unittest 可执行文件中的另一个非常相似的测试用例测试了一个 4k mallocs(后面是 frees),并且在运行时仅扩展了预期的 4GByte。

我不明白:VirtualAlloc 是否有相当高的每次分配开销?如果是这样的话,这显然是页面大小的很大一部分;为什么需要这么多额外的东西,它有什么用?还是我误解了报告的“工作集”的实际含义?这是怎么回事?

更新:引用 Hans 的回答,我注意到这失败了,因为在第二个页面访问中出现了访问冲突,所以无论发生什么事情都不像将分配四舍五入那样简单64K“粒度”。

char*const ptr = reinterpret_cast<char*>(
VirtualAlloc(0, 4096, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE)
);
ptr[0] = 1;
ptr[4096] = 1;

更新:现在在安装了 VisualStudioExpress2013 的 AWS/EC2 Windows2008 R2 实例上,我无法用这个最少的代码(编译的 64 位)重现问题,这显然是开销-免费峰值工作集为 4,335,816K,这是我最初期望看到的数字。因此,要么是我运行的其他机器有什么不同,要么是之前测试中使用的基于 boost-test 的 exe。 Bizzaro,待续...

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

最后更新:抱歉!如果可以的话,我会删除这个问题,因为事实证明,观察到的问题完全是由于测试套件中紧接着的单元测试导致的,该测试套件使用 TBB 的“可扩展分配器”来分配/解除分配几个 GByte的东西。似乎可扩展分配器实际上将此类分配保留在它自己的池中,而不是将它们返回给系统(参见例如 herehere )。一旦我单独运行测试并在它们之后有足够的 Sleep 以观察它们在任务管理器中的完成工作集(是否可以对 TBB 行为做任何事情可能是一个有趣的问题,但作为-这里的问题是一个转移注意力的问题)。

最佳答案

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

您不会得到 4096 字节,它会向上舍入到允许的最小分配。也就是SYSTEM_INFO.dwAllocationGranularity,很久以来都是64KB。这是一种非常基本的地址空间碎片对策。

所以您分配的方式比您想象的要多。

关于c++ - VirtualAlloc 的内存使用率高于预期;这是怎么回事?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20911829/

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