【发布时间】:2016-01-07 18:17:22
【问题描述】:
当内存要求很高时,我正在尝试测试一些 c++ 应用程序的行为,但似乎我无法使用所有可用的 ram。我有以下程序:
class Node {
public:
Node *next;
};
int main() {
int i=0;
Node *first = new Node();
Node *last = first;
//Should be 120000000 * 8 bytes each -> approx 1 GB
for (i=0; i < 120000000; i++) {
Node *node = new Node();
node->next = 0;
last->next = node;
last = last->next;
}
for (i=0; i < 120000000; i++) {
Node *oldfirst = first;
first = first->next;
delete oldfirst;
}
delete first;
return 0;
}
它应该分配大约 1 GB 的数据,因为 Node 类占用 8 个字节。我已经通过 sizeof、gdb 甚至 valgrind 验证了这一点。
然而,这个程序分配了大约 4 GB 的数据!如果我将这个大小加倍( 120000000 -> 2400000000 ),那么有 2 个选项(我的笔记本电脑安装了 8GB 的 RAM):
- 如果我关闭了交换区,进程就会被内核杀死。
- 如果没有,则会发生分页,操作系统变得非常慢。
关键是我无法测试分配 2 GB 数据的应用程序,因为它消耗 8 GB RAM!
我想可能是我请求新Node时分配的字节数超过8(即Node对象的大小),所以我尝试了以下:
class Node {
public:
Node *next;
Node *second_next;
};
int main() {
int i=0;
Node *first = new Node();
Node *last = first;
//Should be 120000000 * 8 bytes each -> approx 1 GB
for (i=0; i < 120000000; i++) {
Node *node = new Node();
node->next = 0;
last->next = node;
last = last->next;
}
for (i=0; i < 120000000; i++) {
Node *oldfirst = first;
first = first->next;
delete oldfirst;
}
delete first;
return 0;
}
现在 Node 对象占用 16 个字节。应用程序的内存占用完全一样! 120000000 导致使用 4 GB 的 RAM,240000000 导致我的应用程序被 Linux 内核杀死。
所以我遇到了this post
C++ 中的每个 new 是否都至少分配 32 个字节?
【问题讨论】:
-
底层分配器的确切行为将取决于操作系统和系统库。当然有可能它会分配一些最小块大小,但是不可能对 C++ 的行为做出一般性断言,就好像你深入挖掘一样,
operator new实际上只是向系统请求内存,可能是通过malloc(). -
听起来您需要使用自定义分配器,或者更好的是,使用链表以外的其他东西。
-
@DavidSchwartz 这只是为了演示 - 它不是生产代码。我想知道一般来说动态分配的对象是如何放置在内存中的。
-
可能是您的操作系统以固定大小的块分配内存吗?因此,如果它以
2^n的块分配,当您请求 120 个字节时,它将分配 128 个字节。如果这是正确的,它将在您请求分配略高于 1GB(2^30字节)时分配2^31字节(2.15GB)。这只是一个猜测。我使用的操作系统会这样做,但使用斐波那契数列来计算块大小。 -
完全可以预期内存分配的开销。我不知道你为什么感到惊讶。您应该意识到这一点并避免分配大量小对象。而是使用矢量。
标签: c++ memory-management malloc new-operator