为什么存储5MB数据的VC ++程序会消耗64MB的系统内存?

时间:2011-06-11 02:45:39

标签: visual-c++ memory allocation

我一直在努力弄清楚为什么我的程序消耗了如此多的系统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" );
}

4 个答案:

答案 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。

感谢您的所有帮助和建议。