我试图更好地理解为什么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字节块,然后释放它们。 自然,这个程序的内存使用量会随着缓冲区的分配而上升,然后在释放缓冲区时会closures。
我在Windows Vista 64-bit上看到的行为是,峰值内存使用量(如任务pipe理器或vmmap报告的)随着时间的推移保持大致恒定,而报告的最低内存使用量增长,直到接近峰值内存使用量。
在Windows 7 64位上报告的最低内存使用量不会随着时间而增长。
编辑:我已经testing了两台配备8 GB / 4 GB RAM的Windows Vista 64位机器和一台配备4 GB RAM的Windows 7 64位机器。 我已经testing了8 GB的机器同时使用低和高内存使用情况。
编辑:我用Visual Studio 2005和2010构build了上面的例子,结果相同。
这个例子没有做任何有用的事情,但是内存使用场景与我的一个程序是类似的(虽然严重压缩了),我试图找出为什么它看起来比实际使用更多的内存。 据我所知,内存是由堆pipe理员持有的。
有没有人有任何关于堆机制的见解? 我是否需要做一些额外的事情来说服堆pipe理器完全释放已使用的堆内存? 我应该使用另外的策略,比如创build一个单独的堆,然后将其销毁?
任何意见或见解都表示赞赏!
难道是低碎片堆 ?
在我看来,我在某些地方读了LFH在Windows 7默认启用。但是,快速搜索没有透露确认,所以我可能在这里是错的。
有一个简单的方法来检查,虽然。 调用从GetProcessHeap获取的句柄上的HeapQueryInformation ,并比较不同系统上的结果。
你在内存压力下试过这个吗? 除非别的东西需要,否则释放内存是没有意义的。
atzz在正确的轨道上,但是这种行为将会发生在任何堆上 – 当你用一个字节的大小调用第一个“new”时,Heap将分配一个“桶”并预先分配一定的内存块多个页面大小,4K); 这样,当相同大小的后续分配进来,它可以很快给你记忆。
此外,当你调用delete的时候,它只是将该区域标记为未分配的,但是如果你想要一个相似大小的新对象,则保留它。
如果堆管理器按照您所描述的方式运行,它将运行得非常慢,因为它必须不断询问内核,“您能给我另一个字节吗? 和“请取消这个!” (事实上,这是不可能的,因为你可以请求内核给你的最小的分配是我记得的页面大小)
释放到堆中的小内存分配通常放置在用于快速分配的列表中。
即使没有这种优化,堆mamager可以自由地保存到从中进行分配的堆桶中。 为了将内存返回到系统(VirtualFree'ed),64KB块中的所有块必须由堆管理器释放和合并。