我试图在内存要求很高时测试一些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!
我认为当我要求新节点时分配的字节数可能超过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 ++中的每个新节点至少分配32个字节是真的吗?
答案 0 :(得分:4)
简短回答 - 你忘了考虑内存分配开销。内存分配器本身需要跟踪已分配的内存块,这些内存本身会占用内存,如果您分配了大量小块,则与您请求的内存量相比,开销会变得过大。然后还要考虑块对齐,许多分配器尝试智能并对齐内存块以获得最佳CPU访问速度,因此它们将与高速缓存行对齐。
最后但并非最不重要的是,一个成功的请求给你8个字节的内存可能会在幕后分配更大的块。毕竟,向malloc / new询问特定数量的内存只能保证您获得至少大小的大小,而不是那个大小。
对于分配大量小块的用例,您需要查看类似于池分配器的内容,以最大限度地减少开销。
实际上,您应该考虑的是比具有大量小节点的非常大的链表更好的数据结构。
答案 1 :(得分:0)
如果您只想了解正在使用的分配,则它具有8字节开销,最小32字节,包括开销和16字节对齐。例如:
1 .. 24字节:需要32
25 .. 40字节:需要48
41 .. 56字节:需要64
等。
如果你想有效地使用大量微小物体,你需要以其他方式分配它们(批量处理,然后自己细分分配)。
答案 2 :(得分:0)
这实际上取决于malloc
实施。我在我的机器上测试了(64位),如果我使用tcmalloc
,它大概需要1GB的内存。内部tcmalloc为不同的分配大小保留单独的池,因此对于每个池,不需要记录对象大小,这减少了小对象的开销。对于8字节分配,根本没有开销。
hidden $ cat c.cpp
#include <iostream>
#include <string>
using namespace std;
struct Node { Node *next; };
int main() {
Node *first = new Node();
Node *last = first;
for (int i=0; i < 120000000; i++) {
Node *node = new Node();
node->next = 0;
last = last->next = node;
}
cout << "Press <Enter> to continue...";
string s;
cin >> s;
return 0;
}
hidden $ g++ -std=c++11 -O3 c.cpp /usr/lib/libtcmalloc_minimal.so.4
hidden $ ./a.out & { sleep 5; ps -C a.out -o rss; killall a.out; }
[1] 31500
Press <Enter> to continue...
[1]+ Stopped ./a.out
RSS
947064