Dar*_*rer 5 c++ memory-leaks stl vector crt
在调查我们的一个项目中的内存链接时,我遇到了一个奇怪的问题。不知何故,当父容器超出范围并且除小对象外无法使用时,为对象分配的内存(shared_ptr 到对象的向量,见下文)并未完全回收。
最小的例子:当程序启动时,我可以毫无问题地分配一个 1.5Gb 的连续块。在我稍微使用内存后(通过创建和销毁一些小对象),我不能再进行大块分配。
测试程序:
#include <iostream>
#include <memory>
#include <vector>
using namespace std;
class BigClass
{
private:
double a[10000];
};
void TestMemory() {
cout<< "Performing TestMemory"<<endl;
vector<shared_ptr<BigClass>> list;
for (int i = 0; i<10000; i++) {
shared_ptr<BigClass> p(new BigClass());
list.push_back(p);
};
};
void TestBigBlock() {
cout<< "Performing TestBigBlock"<<endl;
char* bigBlock = new char [1024*1024*1536];
delete[] bigBlock;
}
int main() {
TestBigBlock();
TestMemory();
TestBigBlock();
}
Run Code Online (Sandbox Code Playgroud)
如果在循环中使用带有 new/delete 或 malloc/free 的普通指针而不是 shared_ptr,问题也会重复。
罪魁祸首似乎是在 TestMemory() 之后,应用程序的虚拟内存保持在 827125760(无论我调用多少次)。因此,没有足够大的免费 VM 区域来容纳 1.5 GB。但我不确定为什么 - 因为我肯定会释放我使用的内存。CRT 是否有一些“性能优化”可以最大限度地减少操作系统调用?
环境为 Windows 7 x64 + VS2012 + 32 位应用程序,无 LAA
小智 3
很抱歉发布另一个答案,因为我无法发表评论;我相信其他许多人都非常接近答案:-)
无论如何,罪魁祸首很可能是地址空间碎片。我猜你正在 Windows 上使用 Visual C++。
C/C++运行时内存分配器(由malloc或new调用)使用Windows堆来分配内存。Windows 堆管理器进行了一项优化,它将保留特定大小限制下的块,以便在应用程序稍后请求类似大小的块时能够重用它们。对于较大的块(我不记得确切的值,但我猜它大约是兆字节),它将直接使用 VirtualAlloc。
其他具有许多小分配模式的长时间运行的 32 位应用程序也存在此问题;让我意识到这个问题的是 MATLAB - 我使用“元胞数组”功能基本上分配了数百万个 300-400 字节的块,即使在释放它们之后,也导致了地址空间碎片的问题。
解决方法是使用 Windows 堆函数(HeapCreate() 等)创建私有堆,通过该堆分配内存(根据需要将自定义 C++ 分配器传递给容器类),然后在需要时销毁该堆。内存恢复 - 这也有一个令人高兴的副作用,即与在循环中删除()无数个块相比,速度非常快。
关于。“内存中剩余的内容”首先导致了问题:“内存中”本身没有剩余任何内容,更多的是释放的块被标记为空闲但未合并的情况。堆管理器有一个地址空间的表/映射,它不允许您分配任何会强制它将可用空间合并到一个连续块中的内容(大概是一种性能启发式方法)。
| 归档时间: |
|
| 查看次数: |
1731 次 |
| 最近记录: |