堆上的内存如何耗尽?

How does memory on the heap get exhausted?

本文关键字:何耗尽 内存      更新时间:2023-10-16

我一直在测试我自己的一些代码,看看耗尽堆或可用存储上的内存需要多少分配内存。但是,除非我的代码在测试中是错误的,否则在堆上可以放置多少内存方面,我会得到完全不同的结果。

我正在测试两个不同的程序。第一个程序在堆上创建矢量对象。第二个程序在堆上创建整数对象。

这是我的代码:

#include <vector>
#include <stdio.h>
int main()
{
long long unsigned bytes = 0;
unsigned megabytes = 0;
for (long long unsigned i = 0; ; i++) {
std::vector<int>* pt1 = new std::vector<int>(100000,10);
bytes += sizeof(*pt1);
bytes += pt1->size() * sizeof(pt1->at(0));
megabytes = bytes / 1000000;
if (i >= 1000 && i % 1000 == 0) {
printf("There are %d megabytes on the heapn", megabytes);
}
}
}

在收到bad_alloc错误之前,此代码的最终输出是:"堆上有 2000 MB">

在第二个程序中:

#include <stdio.h>
int main()
{
long long unsigned bytes = 0;
unsigned megabytes = 0;
for (long long unsigned i = 0; ; i++) {
int* pt1 = new int(10);
bytes += sizeof(*pt1);
megabytes = bytes / 1000000;
if (i >= 100000 && i % 100000 == 0) {
printf("There are %d megabytes on the heapn", megabytes);
}
}
}

在收到bad_alloc错误之前,此代码的最终输出是:"堆上有 511 MB">

两个程序的最终输出大不相同。我对免费商店有什么误解吗?我以为两个结果会大致相同。

平台上new返回的指针很可能是 16 字节对齐的。

如果int4字节,这意味着每new int(10)您将获得 4 个字节,并使 12 个字节无法使用。

仅此一项就可以解释从小分配中获得 500MB 可用空间和从大分配中获得 2000MB 可用空间之间的区别。

最重要的是,跟踪分配的块(至少要跟踪它们的大小以及它们是空闲的还是正在使用的(的开销。 这非常特定于系统的内存分配器,但也会产生每个分配的开销。参见 https://sourceware.org/glibc/wiki/MallocInternals 中的"什么是块",了解glibc分配器的解释。

首先,您必须了解操作系统分配内存以处理称为页面的相当大的内存块(这是一个硬件属性(。页面大小约为 4 -16 kB。

现在标准库尝试以有效的方式使用内存。因此,它必须找到一种方法将页面切成更小的部分并进行管理。为此,必须维护一些有关堆结构的额外信息。

这是很酷的Andrei Alexandrescu cppcon或多或少地谈论它是如何工作的(它省略了有关页面管理的信息(。

因此,当您分配大量小对象时,有关堆结构的信息非常大。另一方面,如果您分配较少数量的较大对象更有效 - 跟踪内存结构的内存更少。

另请注意,有时根据堆策略(当请求小块内存时(,浪费一些内存并返回比请求时更大的内存大小更有效。