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

发布于 2024-11-15 05:23:16 字数 1657 浏览 3 评论 0原文

我一直在努力找出为什么我的程序消耗如此多的系统内存。我正在将文件从磁盘加载到几个动态分配数组的结构向量中。根据任务管理器的说法,一个 16MB 的文件最终会消耗 280MB 的系统 RAM。文件中的类型主要是字符,带有一些短整型和一些长整型。文件中有 331,000 条记录,平均包含约 5 个字段。我将向量转换为结构体,将内存减少到大约 255MB,但这看起来仍然很高。由于向量占用了如此多的内存,程序内存不足,因此我需要找到一种方法来使内存使用更加合理。

我编写了一个简单的程序,只用 1,000,000 个字符指针填充向量(或数组)。我希望它为每个字节分配 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" );
}

I have been working on trying to figure out why my program is consuming so much system RAM. I'm loading a file from disk into a vector of structs of several dynamically allocated arrays. A 16MB file ends up consuming 280MB of system RAM according to task manager. The types in the file are mostly chars with some shorts and a few longs. There are 331,000 records in the file containing on average about 5 fields. I converted the vector to a struct and that reduced the memory to about 255MB but that still seems very high. With the vector taking up so much memory the program is running out of memory so I need to find a way to get the memory usage more reasonable.

I wrote a simple program to just stuff a vector (or array) with 1,000,000 char pointers. I would expect it to allocate 4+1 bytes for each giving 5MB of memory required for storage, but in fact it is using 64MB (array version) or 67MB (vector version). When the program first starts up it only consumes 400K so why is there an additional 59MB for array or 62MB for vectors being allocated? This extra memory seems to be for each container, so if I create a size_check2 and copy everything and run it the program uses up 135MB for 10MB worth of pointers and data.

Thanks in advance,

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" );
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

千紇 2024-11-22 05:23:16

在我使用 VS2010 的测试中,调试版本的工作集大小为 52,500KB。但是发布版本有一个工作集
大小为 20,944KB。

调试构建通常会比优化构建使用更多的内存,因为调试堆管理器执行诸如创建 内存栅栏

在发布版本中,我怀疑堆管理器保留的内存比您实际使用的内存更多,以进行性能优化。

In my test using VS2010, a debug build had a working set size of 52,500KB. But a release build had a working set
size of 20,944KB.

Debug builds will usually use more memory than optimized builds due to the debug heap manager doing things like creating memory fences.

In release builds, I suspect that the heap manager reserves more memory than you are actually using as a performance optimization.

(り薆情海 2024-11-22 05:23:16

内存泄漏

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?
}

此外,请确保您已在发布模式下编译

Memory Leak

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?
}

Furthermore, make sure you've compiled in release mode

小瓶盖 2024-11-22 05:23:16

您在测试程序中看到如此大的内存占用可能有几个原因。在您的

void size_check::stuff_me( unsigned int howMany )
{

This 方法中,始终会使用 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) == 8bytes。

内存消耗的增加可能与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-5 MB。

There might be a couple reasons why you're seeing such a large memory footprint from your test program. Inside your

void size_check::stuff_me( unsigned int howMany )
{

This method is always getting called with howMany = 50000.

package = new size_type[howMany];

Assuming this is on a 32-bit setup the above statement will allocate 50,000 * 4 bytes.

for( unsigned int i = 0; i < howMany; ++i )
{
    size_type *me = new size_type;

The above will allocate new storage on each iteration of the loop. Since this loops 50,000 and the allocation never gets deleted that effectively takes up another 50,000 * 4 bytes upon loop completion.

        *me = 33;
        package[i] = *me;
    }
}

Lastly, since stuff_me() gets called 20 times from main() your program would have allocated at least ~8Mbytes upon completion. If this is on a 64-bit system than the footprint will likely double since sizeof(long) == 8bytes.

The increase in memory consumption could have something to do with the way VS implements dynamic allocation. For performance reasons, it's possible that due to the multiple calls to new your program is reserving extra memory so as to avoid hitting up the OS everytime it needs more.

FYI, when I ran your test program on mingw-gcc 4.5.2, the memory consumption was ~20Mbytes -- much lower than what you were seeing but still a substantial amount. If I changed the stuff_me method to this:

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;
}

memory consumption goes down quite a bit down to ~4-5mbytes.

黯然 2024-11-22 05:23:16

我想我通过深入研究新的声明找到了答案。在调试版本中,当您执行新操作时会创建两个项目。一种是 _CrtMemBlockHeader,长度为 32 字节。另一个是 noMansLand(内存栅栏),大小为 4 字节,每个新的开销为 36 字节。就我而言,每个新的字符都会花费 37 个字节。在发布版本中,内存使用量减少到大约 1/2,但我无法确切地知道为每个 new 分配了多少内存,因为我无法进入 new/malloc 例程。

所以我的解决方法是分配一大块内存来将文件保存在内存中。然后解析内存映像,填充指向每个记录开头的指针向量。然后根据需要,我使用指向所选记录开头的指针从内存映像构建记录。这样做可以将内存占用量减少到 <25MB。

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

I think I found the answer by delving into the new statement. In debug builds there are two items that are created when you do a new. One is _CrtMemBlockHeader which is 32 bytes in length. The other is noMansLand (a memory fence) with a size of 4 bytes which gives us an overhead of 36 bytes for each new. In my case each individual new for a char was costing me 37 bytes. In release builds the memory usage is reduced to about 1/2 but I can't tell exactly how much is allocated for each new as I can't get to the new/malloc routine.

So my work around is to allocate a large block of memory to hold the file in memory. Then parse the memory image filling in a vector of pointers to the beginning of each of the records. Then on demand, I build a record from the memory image using the pointer to the beginning of the selected record. Doing this reduced the memory footprint to <25MB.

Thanks for all your help and suggestions.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文