0

这是我在 Windows 7 下的 MSVC++ 2010 上做的一个简单测试:

// A struct with sizeof(s) == 4, e.g 4 bytes
struct s
{
    int x;
};

// Allocate 1 million structs
s* test1 = new s[1000000];

// Memory usage show that the increase in memory is roughly 4 bytes * 1000000 - As expected
// NOW! If I run this:
for (int i = 0; i < 1000000; i++)
    new s();

// The memory usage is disproportionately large. When divided by 1000000, indicates 64 bytes per s!!!

这是常识还是我遗漏了什么?之前我总是在需要时动态创建对象。例如,网格中每个三角形的 new Triangle() 等。

单个实例的动态内存分配确实存在数量级的开销吗?

干杯

编辑:

刚刚在 Windows XP 上使用 g++ 编译并运行相同的程序:现在开销是 16 个字节,而不是之前观察到的 64 个字节!很有意思。

4

4 回答 4

3

不一定,但操作系统通常会代表您以它认为方便的任何大小的块来保留内存;在您的系统上,我猜它会为每个请求提供 64 字节的倍数。

毕竟,跟踪内存分配会产生开销,而且保留非常少量的内存是不值得的。

于 2010-07-19T01:18:58.133 回答
1

那是为了调试版本吗?因为在调试构建中,msvc 将在对象周围分配“警卫”,以查看您是否覆盖了对象边界。

于 2010-07-19T01:16:48.420 回答
1

任何单个内存分配通常都会产生开销。现在这是根据我的知识malloc而不是new但我怀疑它是一样的。

内存区域的一部分,当被划分为(比如说)30字节的分配时,通常会有一个标题(例如,16字节,所有类似的数字只是下面的例子,它们可能不同)并且可以被填充为 16 字节的倍数,以便于竞技场管理。

标头通常很重要,它允许在您完成后将部分重新集成到空闲内存池中。

它至少包含有关块大小的信息,并且可能还具有内存保护(以检测竞技场的损坏)。

因此,当您分配一百万个结构数组时,您会发现它使用了额外的 16 个字节作为标头(400 万和 16 个字节)。当您尝试分配一百万个单独的结构时,它们中的每一个都会有这种开销。

我在这里回答了一个相关问题,并提供了更多详细信息。我怀疑C++ 需要更多的标头信息,因为它可能必须存储超过节大小的项目数(用于正确的析构函数调用),但这只是我的假设。它不影响每个分配项目需要某种会计信息这一事实。

如果您真的想了解空间的用途,则需要深入研究 MSVC 运行时源代码。

于 2010-07-19T01:25:17.727 回答
1

您应该检查malloc实施。可能这会澄清一些事情。

不确定是否malloc可以在某处查看 MSVC++。如果不是,请查看其他一些实现,它们可能在某种程度上相似。

不要期望malloc实现很容易。它需要在分配的虚拟页面中寻找一些空闲空间或者分配一个新的虚拟页面。它必须快速做到这一点。尽可能快。它必须是多线程安全的。也许您的malloc实现有某种位向量,它可以保护某些页面中哪些 64 位块是空闲的,并且它只占用下一个空闲块。

于 2010-07-19T01:48:37.200 回答