我试图更好地理解Windows Vista堆的行为方式。考虑以下非常简单的程序:
#include <vector>
#define NUM_ALLOCS 10000000
int _tmain(int argc, _TCHAR* argv[])
{
for (int iteration=0; iteration<10000; ++iteration) {
std::vector<unsigned char *> buffer;
buffer.reserve(NUM_ALLOCS);
for (int i=0;i<NUM_ALLOCS;++i) {
buffer.push_back(new unsigned char);
}
for (int i=0;i<NUM_ALLOCS;++i) {
delete buffer[i];
}
}
return 0;
}
基本上这是一个循环,每次迭代分配大量1字节块然后释放它们。当然,这个程序的内存使用量在分配缓冲区时会上升,然后在缓冲区释放时会下降。
我在Windows Vista 64位上看到的行为是峰值内存使用量(由任务管理器或vmmap报告)随时间保持大致不变,而报告的最低内存使用量增长直到它接近峰值内存使用量。
在Windows 7 64位上,报告的最低内存使用量不会随着时间的推移而增长。
编辑:我已经在两台配备8 GB / 4 GB RAM的Windows Vista 64位计算机和一台装有4 GB RAM的Windows 7 64位计算机上进行了测试。我已经测试了8 GB机器的低内存和高内存使用情况。
编辑:我使用Visual Studio 2005和2010构建了上面的示例,结果相同。
这个例子没有做任何有用的事情,但内存使用场景与我的程序类似(虽然非常紧凑),我试图弄清楚为什么它似乎使用了比实际更多的内存确实。据我所知,内存由堆管理器保存。
有没有人对堆机制有任何见解? 我是否需要做一些额外的事情来说服堆管理器完全释放使用过的堆内存?是否有我应该使用的替代策略,例如创建一个单独的堆然后销毁它?
感谢任何评论或见解!
答案 0 :(得分:1)
在我看来,我在Windows 7上默认启用了LFH。但是,快速搜索没有显示确认信息,所以我可能在这里错了。
但是有一种简单的方法可以检查。在从HeapQueryInformation获得的句柄上调用GetProcessHeap,并比较不同系统上的结果。
答案 1 :(得分:0)
你是否在内存压力下试过这个?除非其他东西需要,否则释放内存是没有意义的。
答案 2 :(得分:0)
atzz在正确的轨道上,但这种行为将发生在任何堆中 - 当你用一个字节大小调用第一个“new”时,Heap将分配一个“桶”并预分配一个特定的内存块(可能是页面大小的倍数,4K);这样,当相同大小的后续分配进入时,它可以非常快地给你记忆。
此外,当您调用delete时,它只是将该区域标记为未分配,但保留它以防您以后想要一个类似大小的新对象。
如果堆管理器按照你的描述操作,那么它的运行速度会非常慢,因为它必须经常询问内核,“你能再给我一个字节吗?”和“取悦这个!” (事实上,这是不可能的,因为你可以要求内核给你的最小分配是页面大小,我记得)
答案 3 :(得分:0)
对堆免费的小内存分配通常放在用于快速分配的列表中。
即使没有这种优化,堆mamager也可以自由地保存到进行分配的堆桶中。为了将内存返回给系统(VirtualFree'ed),64KB块中的所有块必须由堆管理器释放并组合。