我刚刚写了一些处理大对象的线程代码。即使我从一个对象清理所有东西(没有删除它),它仍然吃掉GB的RAM。仅供参考,我在较小的环境中重现了这个问题。
此代码创建一个结构和一个包含指向结构的指针向量的对象。然后我用一些指向结构的指针填充对象(用new创建)。我想对象应该只拥有指针的大小,而不是所有尖头结构的大小,但是当我运行代码时,对象的大小使用300mb。
当我删除向量的所有成员然后清除向量时,占用的内存(但现在未使用)仍然很高。释放此内存的唯一方法似乎是删除包含该向量的整个对象。如果它只是一个指针向量,为什么向量会占用这么大的RAM?如何在不删除和重新创建对象的情况下释放它?
function -> void f_create_heapCleaner_string
创建一个字符串然后删除它。有时候这个技巧会清理堆。
#include <string>
#include <malloc.h>
#include <vector>
#include <iostream>
using namespace std;
struct struct_test_struct {
string s_internal_data;
};
struct struct_test_struct* BASEDATA_struct_test_struct;
class objhandle_TestStruct__class {
public:
vector<struct struct_test_struct *> v_pointer_TestStruct;
unsigned int ui_v_size;
objhandle_TestStruct__class() {
ui_v_size = 3000;
}
void f_create_heapCleaner_string() {
string * s_tmp = new string();
(*s_tmp).assign(1000000, '*');
(*s_tmp) = "";
delete s_tmp;
}
void f_create_vector(unsigned int ui_size_str) {
cout << " f_create_vector() start " << endl;
malloc_stats();
for (unsigned int ui = 0; ui < ui_v_size; ui++) {
struct struct_test_struct * tmp_newstruct = new struct_test_struct();
(*tmp_newstruct).s_internal_data.assign((ui_size_str + ui), '*');
v_pointer_TestStruct.push_back(tmp_newstruct);
}
cout << " f_create_vector() end " << endl;
malloc_stats();
}
void f_delete_vector_content() {
cout << " f_delete_vector_content() start " << endl;
malloc_stats();
for (unsigned int ui = 0; ui < ui_v_size; ui++) {
delete v_pointer_TestStruct[ui];
}
f_create_heapCleaner_string();
cout << " f_delete_vector_content() end " << endl;
malloc_stats();
}
void f_clear_vector() {
cout << " f_clear_vector() start " << endl;
malloc_stats();
v_pointer_TestStruct.clear();
f_create_heapCleaner_string();
cout << " f_clear_vector() end " << endl;
malloc_stats();
}
void f_RUN_FULL_TEST(unsigned int ui_size_str) {
cout << " .... start test with string size of = " << ui_size_str << endl;
f_create_vector(ui_size_str);
f_delete_vector_content();
f_clear_vector();
}
};
int main(int argc, char**argv) {
objhandle_TestStruct__class * ptr_objhandle_TestStruct__class = new objhandle_TestStruct__class();
(*ptr_objhandle_TestStruct__class).f_RUN_FULL_TEST(100000);
(*ptr_objhandle_TestStruct__class).f_RUN_FULL_TEST(10000);
cout << " DELETE OBJECT start " << endl;
malloc_stats();
delete ptr_objhandle_TestStruct__class;
cout << " DELETE OBJECT finished " << endl;
malloc_stats();
return 0;
}
---编译: g ++ -o a test.cc
然后 ./a
输出:
.... start test with string size of = 100000
f_create_vector() start
Arena 0:
system bytes = 135168
in use bytes = 48
Total (incl. mmap):
system bytes = 135168
in use bytes = 48
max mmap regions = 0
max mmap bytes = 0
f_create_vector() end
Arena 0:
system bytes = 309997568
in use bytes = 309972064
Total (incl. mmap):
system bytes = 309997568
in use bytes = 309972064
max mmap regions = 0
max mmap bytes = 0
f_delete_vector_content() start
Arena 0:
system bytes = 309997568
in use bytes = 309972064
Total (incl. mmap):
system bytes = 309997568
in use bytes = 309972064
max mmap regions = 0
max mmap bytes = 0
f_delete_vector_content() end
Arena 0:
system bytes = 309997568
in use bytes = 32832
Total (incl. mmap):
system bytes = 309997568
in use bytes = 32832
max mmap regions = 0
max mmap bytes = 0
f_clear_vector() start
Arena 0:
system bytes = 309997568
in use bytes = 32832
Total (incl. mmap):
system bytes = 309997568
in use bytes = 32832
max mmap regions = 0
max mmap bytes = 0
f_clear_vector() end
Arena 0:
system bytes = 309997568
in use bytes = 32832
Total (incl. mmap):
system bytes = 309997568
in use bytes = 32832
max mmap regions = 0
max mmap bytes = 0
.... start test with string size of = 10000
f_create_vector() start
Arena 0:
system bytes = 309997568
in use bytes = 32832
Total (incl. mmap):
system bytes = 309997568
in use bytes = 32832
max mmap regions = 0
max mmap bytes = 0
f_create_vector() end
Arena 0:
system bytes = 309997568
in use bytes = 40094656
Total (incl. mmap):
system bytes = 309997568
in use bytes = 40094656
max mmap regions = 0
max mmap bytes = 0
f_delete_vector_content() start
Arena 0:
system bytes = 309997568
in use bytes = 40094656
Total (incl. mmap):
system bytes = 309997568
in use bytes = 40094656
max mmap regions = 0
max mmap bytes = 0
f_delete_vector_content() end
Arena 0:
system bytes = 250077184
in use bytes = 32832
Total (incl. mmap):
system bytes = 250077184
in use bytes = 32832
max mmap regions = 0
max mmap bytes = 0
f_clear_vector() start
Arena 0:
system bytes = 250077184
in use bytes = 32832
Total (incl. mmap):
system bytes = 250077184
in use bytes = 32832
max mmap regions = 0
max mmap bytes = 0
f_clear_vector() end
Arena 0:
system bytes = 250077184
in use bytes = 32832
Total (incl. mmap):
system bytes = 250077184
in use bytes = 32832
max mmap regions = 0
max mmap bytes = 0
DELETE OBJECT start
Arena 0:
system bytes = 250077184
in use bytes = 32832
Total (incl. mmap):
system bytes = 250077184
in use bytes = 32832
max mmap regions = 0
max mmap bytes = 0
DELETE OBJECT finished
Arena 0:
system bytes = 135168
in use bytes = 0
Total (incl. mmap):
system bytes = 135168
in use bytes = 0
max mmap regions = 0
max mmap bytes = 0
谢谢你, 弗朗西斯
--------------编辑 在对象和结构之间使用和对象容器,这会在删除时释放内存。 struct struct_test_struct { string s_internal_data; };
class objstruct_test_struct_OWNER {
public:
vector<struct struct_test_struct *> v_pointer_TestStruct;
};
class objhandle_TestStruct__class {
public:
class objstruct_test_struct_OWNER * ptr_OBJ;
unsigned int ui_v_size;
objhandle_TestStruct__class() {
ui_v_size = 3000;
}
.........
void f_create_vector(unsigned int ui_size_str) {
.....
ptr_OBJ = new objstruct_test_struct_OWNER();
cout << " f_create_vector() start " << endl;
malloc_stats();
for (unsigned int ui = 0; ui < ui_v_size; ui++) {
struct struct_test_struct * tmp_newstruct = new struct_test_struct();
(*tmp_newstruct).s_internal_data.assign((ui_size_str + ui), '*');
(*ptr_OBJ).v_pointer_TestStruct.push_back(tmp_newstruct);
}
.........
void f_clear_vector() {
.........
delete ptr_OBJ;
.........
通过这种方式程序工作,这是输出
.... start test with string size of = 100000
f_create_vector() start
Arena 0:
system bytes = 135168
in use bytes = 64
Total (incl. mmap):
system bytes = 135168
in use bytes = 64
max mmap regions = 0
max mmap bytes = 0
f_create_vector() end
Arena 0:
system bytes = 309997568
in use bytes = 309972080
Total (incl. mmap):
system bytes = 309997568
in use bytes = 309972080
max mmap regions = 0
max mmap bytes = 0
f_delete_vector_content() start
Arena 0:
system bytes = 309997568
in use bytes = 309972080
Total (incl. mmap):
system bytes = 309997568
in use bytes = 309972080
max mmap regions = 0
max mmap bytes = 0
f_delete_vector_content() end
Arena 0:
system bytes = 309997568
in use bytes = 32848
Total (incl. mmap):
system bytes = 309997568
in use bytes = 32848
max mmap regions = 0
max mmap bytes = 0
f_clear_vector() start
Arena 0:
system bytes = 309997568
in use bytes = 32848
Total (incl. mmap):
system bytes = 309997568
in use bytes = 32848
max mmap regions = 0
max mmap bytes = 0
f_clear_vector() end
Arena 0:
system bytes = 135168
in use bytes = 32
Total (incl. mmap):
system bytes = 135168
in use bytes = 32
max mmap regions = 1
max mmap bytes = 1007616
.... start test with string size of = 10000
f_create_vector() start
Arena 0:
system bytes = 135168
in use bytes = 64
Total (incl. mmap):
system bytes = 135168
in use bytes = 64
max mmap regions = 1
max mmap bytes = 1007616
f_create_vector() end
Arena 0:
system bytes = 40161280
in use bytes = 40094816
Total (incl. mmap):
system bytes = 40161280
in use bytes = 40094816
max mmap regions = 1
max mmap bytes = 1007616
f_delete_vector_content() start
Arena 0:
system bytes = 40161280
in use bytes = 40094816
Total (incl. mmap):
system bytes = 40161280
in use bytes = 40094816
max mmap regions = 1
max mmap bytes = 1007616
f_delete_vector_content() end
Arena 0:
system bytes = 40161280
in use bytes = 32848
Total (incl. mmap):
system bytes = 40161280
in use bytes = 32848
max mmap regions = 1
max mmap bytes = 1007616
f_clear_vector() start
Arena 0:
system bytes = 40161280
in use bytes = 32848
Total (incl. mmap):
system bytes = 40161280
in use bytes = 32848
max mmap regions = 1
max mmap bytes = 1007616
f_clear_vector() end
Arena 0:
system bytes = 1138688
in use bytes = 32
Total (incl. mmap):
system bytes = 1138688
in use bytes = 32
max mmap regions = 1
max mmap bytes = 1007616
DELETE OBJECT start
Arena 0:
system bytes = 1138688
in use bytes = 32
Total (incl. mmap):
system bytes = 1138688
in use bytes = 32
max mmap regions = 1
max mmap bytes = 1007616
DELETE OBJECT finished
Arena 0:
system bytes = 1138688
in use bytes = 0
Total (incl. mmap):
system bytes = 1138688
in use bytes = 0
max mmap regions = 1
max mmap bytes = 1007616
我在这里只显示的问题是对象似乎为自己保留了已分配的内存,直到没有被删除,所以似乎只为我的设备释放内存的方法是将数据放入另一个子对象并删除它..
-------------------终于.. 我已经发现,当程序保留一部分内存映射以供将来使用时,这会被重新使用,因为我们都知道并且没关系..我的多线程程序的问题是malloc创建这些“Arenas”并且当2 malloc时在一个大对象内同一时刻调用malloc创建另一个“竞技场”为它保留一个新的内存映射..在我的程序中我最终没有自由ram,4个“Arenas”每个映射超过3gb ram ,但每个真的使用不到100mb!所以问题是内存映射(〜不可能手动释放)和线程访问内存,将这个未使用的ram乘以这些“Arenas”,所以我在访问这些对象时为所有线程创建一个mutex_lock,所以这些都保存在相同的竞技场没有“浪费”记忆(已映射但未使用)进入多个竞技场..
我希望我已经解释了一下我的问题和解决方案..希望这可以帮助其他人;) 再次感谢你, 弗朗西斯
-----我还在测试..我也见过这个 http://google-perftools.googlecode.com/svn/trunk/doc/tcmalloc.html 他们确切地说我的问题是什么..“在ptmalloc2中,内存永远不能从一个竞技场转移到另一个竞技场。这可能会导致大量浪费的空间。”并创建一个不同的内存分配器,应该有所帮助..
答案 0 :(得分:1)
如果没有malloc_stats的源代码,很难准确知道您的报告内容。
但要考虑的一件事是,如果您要报告系统页面,即使释放C / C ++使用的内存(使用删除或免费),也不会释放这些页面。原因是当您使用new / malloc分配内存时,C运行时库将请求一段系统内存,然后细分该内存块以满足您的请求。分配一大块内存时也是如此。 C RTL将分配一大块系统内存,将该内存添加到其已知的可用C RTL内存块列表中,然后返回指向大块内存的指针。
这里的关键是对于大多数标准分配器(并非全部,甚至可能不是您正在使用的分配器),当您释放内存时,该内存不会返回到操作系统但保留在列表中可用于未来新闻和mallocs的内存。
因此,如果您在系统页面方面显示可用内存,那么当您免费使用时,您将看不到该号码。
答案 1 :(得分:1)
看看Boost's shared pointer。尝试在您的代码中实现它,这将消除您对delete
的需求。基本上,将矢量更改为:
vector<boost::shared_ptr<struct struct_test_struct> > v_pointer_TestStruct;
并且
boost::shared_ptr<struct_test_struct> tmp_newstruct( new struct_test_struct() );
...您可以完全删除此代码:
for (unsigned int ui = 0; ui < ui_v_size; ui++) {
delete v_pointer_TestStruct[ui];
}
由于对v_pointer_TestStruct.clear();
的调用将从现在开始内部执行此操作。这将基本上为您处理所有内存分配(至少为此结构)。
答案 2 :(得分:1)
您需要确保完全理解malloc_stats返回的内容。
我不能比指着你this great post更好。下面的片段..
那么,系统字节是, 显然,为系统保留的字节数。这意味着他们是 适用于操作系统和梯级2及以下库,但不适用于 你的程序,通常在Prerog Ladder的Rung 4上运行。在 遗憾的是,使用字节是库中的拼写错误;它应该在 use_r_ bytes,表示用户空间中剩余的字节数(行5和 以上)当前的计划。
答案 3 :(得分:0)
执行vector.clear()
设置vector.size()== 0,但不保证vector.capacity()
的任何内容。换句话说,标准允许std :: vector保持其内存分配,以防你再次用数据填充它。
要使向量释放其内存,请使用Clear-and-minimize idiom:
vector<struct struct_test_struct *> tmp_empty_vector;
v_pointer_TestStruct.swap(tmp_empty_vector);