我一直在努力弄清楚为什么我的程序消耗了如此多的系统RAM。我正在从磁盘加载一个文件到几个动态分配的数组的结构向量。根据任务经理的说法,一个16MB的文件最终消耗280MB的系统RAM。文件中的类型主要是带有一些短裤和一些长片的字符。该文件中有331,000条记录,平均包含5个字段。我将向量转换为结构,并将内存减少到大约255MB,但仍然看起来非常高。由于向量占用了大量内存,程序内存不足,因此我需要找到一种方法来使内存使用更加合理。
我编写了一个简单的程序来填充带有1,000,000个char指针的向量(或数组)。我希望它为每个分配4 + 1个字节,为存储提供5MB内存,但实际上它使用64MB(阵列版本)或67MB(矢量版本)。当程序首次启动时它只消耗400K,那么为什么阵列需要额外的59MB或分配矢量为62MB?这个额外的内存似乎是针对每个容器的,所以如果我创建一个size_check2并复制所有内容并运行它,那么程序会使用135MB来获取10MB的指针和数据。
提前致谢,
size_check.h
#pragma once
#include <vector>
class size_check
{
public:
size_check(void);
~size_check(void);
typedef unsigned long size_type;
void stuff_me( unsigned int howMany );
private:
size_type** package;
// std::vector<size_type*> package;
size_type* me;
};
size_check.cpp
#include "size_check.h"
size_check::size_check(void)
{
}
size_check::~size_check(void)
{
}
void size_check::stuff_me( unsigned int howMany )
{
package = new size_type*[howMany];
for( unsigned int i = 0; i < howMany; ++i )
{
size_type *me = new size_type;
*me = 33;
package[i] = me;
// package.push_back( me );
}
}
的main.cpp #include“size_check.h”
int main( int argc, char * argv[ ] )
{
const unsigned int buckets = 20;
const unsigned int size = 50000;
size_check* me[buckets];
for( unsigned int i = 0; i < buckets; ++i )
{
me[i] = new size_check();
me[i]->stuff_me( size );
}
printf( "done.\n" );
}
答案 0 :(得分:3)
在我使用VS2010的测试中,调试版本的工作集大小为52,500KB。但是发布版本有一个工作集 大小为20,944KB。
由于调试堆管理器执行诸如创建memory fences之类的操作,因此调试版本通常会使用比优化版本更多的内存。
在发布版本中,我怀疑堆管理器会保留比实际用作性能优化更多的内存。
答案 1 :(得分:1)
内存泄漏
package = new size_type[howMany]; // instantiate 50,000 size_type's
for( unsigned int i = 0; i < howMany; ++i )
{
size_type *me = new size_type; // Leak: results in an extra 50k size_type's being instantiated
*me = 33;
package[i] = *me; // Set a non-pointer to what is at the address of pointer "me"
// Would package[i] = 33; not suffice?
}
此外,请确保您已在发布模式下编译
答案 2 :(得分:1)
可能有几个原因导致您从测试程序中看到如此大的内存占用。在你的
里面void size_check::stuff_me( unsigned int howMany )
{
此方法始终使用howMany
= 50000进行调用。
package = new size_type[howMany];
假设这是在32位设置上,上面的语句将分配50,000 * 4字节。
for( unsigned int i = 0; i < howMany; ++i )
{
size_type *me = new size_type;
以上将在循环的每次迭代中分配新存储。因为这会循环50,000并且分配永远不会被删除,在循环完成时有效占用另外50,000 * 4个字节。
*me = 33;
package[i] = *me;
}
}
最后,由于stuff_me()
从main()
被调用20次,因此您的程序在完成时将分配至少〜8Mbytes。如果这是在64位系统上,那么从sizeof(long)
== 8字节开始,占用空间可能会翻倍。
内存消耗的增加可能与VS实现动态分配的方式有关。出于性能原因,由于对new
的多次调用,您的程序可能会保留额外的内存,以避免每次需要更多操作时都操作操作系统。
仅供参考,当我在mingw-gcc 4.5.2上运行你的测试程序时,内存消耗大约为20Mbytes - 比你看到的要低得多,但仍然是一个很大的数量。如果我将stuff_me方法更改为:
void size_check::stuff_me( unsigned int howMany )
{
package = new size_type[howMany];
size_type *me = new size_type;
for( unsigned int i = 0; i < howMany; ++i )
{
*me = 33;
package[i] = *me;
}
delete me;
}
内存消耗量下降到相当于〜4-5mbytes。
答案 3 :(得分:1)
我想通过深入研究新陈述找到了答案。在调试版本中,执行新操作时会创建两个项目。一个是_CrtMemBlockHeader,长度为32个字节。另一个是noMansLand(一个内存栅栏),大小为4个字节,这为我们提供了每个新字节36字节的开销。在我的情况下,每个新的char都花费了我37个字节。在发布版本中,内存使用量减少到大约1/2,但我无法确切地知道为每个新内容分配了多少,因为我无法进入新的/ malloc例程。
所以我的工作是分配一大块内存来将文件保存在内存中。然后解析填充在指向每个记录开头的指针向量的内存图像。然后根据需要,我使用指向所选记录开头的指针从内存映像构建一条记录。这样做可以将内存占用减少到<25MB。
感谢您的所有帮助和建议。