简体   繁体   English

c + +未使用的仅包含指针的对象的内存,如何释放?

[英]c++ unused memory of objects containing only pointers , how to free?

I've just written some threaded code which handles huge objects. 我刚刚编写了一些处理大型对象的线程代码。 Even when I clean up everything from an object (without deleting it), it keep eating GBs of RAM. 即使我清理了一个对象的所有内容(不删除它),它仍然占用GB的RAM。 FYI, I reproduced the issue in a smaller environment. 仅供参考,我在较小的环境中重现了该问题。

This code creates a structure and an object containing a vector of pointers to the structure. 此代码创建一个结构和一个对象,其中包含指向该结构的指针的向量。 Then I fill the object with some pointers to the structure (created with new). 然后,我用一些指向结构的指针填充对象(用new创建)。 I suppose that the object should own only the size of the pointers, not the size of all pointed structures, but when I run the code, the size of the object uses 300mb. 我想该对象应该只拥有指针的大小,而不是所有指向的结构的大小,但是当我运行代码时,该对象的大小使用300mb。

When I delete all members of the vector and then clean the vector, the memory occupied (but unused now ) remains high. 当我删除向量的所有成员然后清理向量时,占用的内存(但现在未使用)仍然很高。 The only way to free this memory seems to be deleting the whole object which contained the vector. 释放此内存的唯一方法似乎是删除包含向量的整个对象。 Why does the vector keep so much occupied RAM if it was only a vector of pointer? 如果向量只是指针向量,为什么向量会保留这么多占用的RAM? How can I free it without having to delete and re-create the object? 如何释放它而不必删除并重新创建对象?

The function -> void f_create_heapCleaner_string creates a string then deletes it. function -> void f_create_heapCleaner_string创建一个字符串,然后将其删除。 Sometimes the heap is cleaned by this trick. 有时,此技巧可以清除堆。

#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;
}

--- compile with: g++ -oa test.cc ---编译:g ++ -oa test.cc

then ./a 然后./a

Output: 输出:

    .... 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

Thank you, Francesco 谢谢弗朗切斯科

-------------- edit using and object container between the object and the structure, this release the memory when deleted.. struct struct_test_struct { string s_internal_data; --------------在对象和结构之间使用和对象容器进行编辑,这将在删除时释放内存。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;
 .........

by this way the program works, this is the output 通过这种方式程序可以工作,这就是输出

 .... 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

my issue that i'm only showing here is that objects seems to keep allocated memory for themselves till are not deleted, so seems that only way to free memory for my appliance is to place data into another sub-object and deleting it.. 我只在这里显示的问题是,对象似乎一直为自己分配已分配的内存,直到不删除为止。因此,为设备释放内存的唯一方法似乎是将数据放入另一个子对象并删除它。

------------------- finally.. i've found that when the program keep a portion of memory mapped for future utilization, this is re-used as we all know and that's ok.. the problem on my multithreaded program was that malloc create these "Arenas" and when 2 malloc are called in the same moment inside a big object malloc create another "Arena" reserving a new map of memory for it.. in my program i finally end having no free ram, with 4 "Arenas" having mapped more than 3gb of ram each, but really using less than 100mb each! -------------------最后..我发现,当程序保留一部分内存以供将来使用时,众所周知,这已被重用。没关系..我的多线程程序上的问题是malloc创建了这些“ Arenas”,并且在同一时刻在一个大对象malloc中调用了2个malloc时,创建了另一个“ Arena”,为其保留了新的内存映射。程序我最终以没有免费的ram结束,有4个“ Arenas”映射了超过3gb的ram,但实际上每个映射不到100mb! so the problem was both memory mapping (~impossible to free manually) and threaded access to memory wich multiply this unused ram into these "Arenas" , so i create a mutex_lock to all thread when accessing to these objects, so these are kept into the same Arena without "wasting" memory (mapped but not used) into multiple arenas.. 因此,问题在于内存映射(无法手动释放)和线程访问内存,将未使用的ram乘以这些“ Arenas”,因此在访问这些对象时我为所有线程创建了一个mutex_lock,因此将它们保留在相同的竞技场,没有“浪费”内存(映射但未使用)进入多个区域。

i hope i have explained a bit my issue and resolution.. hope this could help someone else ;) thank you again, Francesco 我希望我已经解释了我的问题和解决方法..希望这可以对其他人有所帮助;)再次感谢您,弗朗切斯科

----- i still testing.. i've seen also this http://google-perftools.googlecode.com/svn/trunk/doc/tcmalloc.html they say exactly what my issue was.. "In ptmalloc2 memory can never move from one arena to another. This can lead to huge amounts of wasted space. " and create a different memory allocator wich should help.. -----我仍在测试。.我也看到了这个http://google-perftools.googlecode.com/svn/trunk/doc/tcmalloc.html,他们说的正是我的问题。““在ptmalloc2内存中永远不能从一个领域移动到另一个领域。这可能会导致大量的空间浪费。”并创建一个不同的内存分配器应该会有所帮助。

Without the source code to malloc_stats, it is hard to know exactly what you are reporting. 如果没有malloc_stats的源代码,则很难确切知道您要报告的内容。

One thing to consider however, is that if you are reporting system pages, those pages will not be freed even after you free the memory used by C/C++ (using delete or free). 但是,要考虑的一件事是,如果您要报告系统页面,则即使您释放了C / C ++所使用的内存(使用delete或free),也不会释放这些页面。 The reason being is that when you allocate memory using new/malloc, the C runtime library will request a segment of system memory and then subdivide that block of memory to satisfy your request. 原因是当您使用new / malloc分配内存时,C运行时库将请求一段系统内存,然后再细分该内存块以满足您的请求。 The same is true when you allocate a HUGE chunk of memory. 分配巨大的内存块时也是如此。 the C RTL will allocate a large block of system memory, add that memory to its list of known blocks of available C RTL memory and then return you a pointer to a huge block of memory. C RTL将分配一个大的系统内存块,将该内存添加到其可用C RTL内存的已知块列表中,然后返回指向巨大内存块的指针。

The key here is that for most standard allocators (not all and maybe not even the one you are using), when you free the memory, that memory isn't going to be returned to the operating system but kept in the list of available memory for future news and mallocs. 这里的关键是对于大多数标准分配器(不是全部,甚至可能不是您正在使用的分配器),当释放内存时,该内存不会返回给操作系统,而是保留在可用内存列表中有关将来的新闻和malloc。

So if you are showing free memory in terms of system pages, you won't see that number go down when you do your free. 因此,如果按照系统页面显示可用内存,那么在您免费使用时,该数字不会减少。

Take a look at Boost's shared pointer . 看一下Boost的共享指针 Try to implement it in your code, which will eliminate your need for delete s. 尝试在您的代码中实现它,这将消除对delete的需要。 Basically, change your vector to: 基本上,将向量更改为:

vector<boost::shared_ptr<struct struct_test_struct> > v_pointer_TestStruct;

And

boost::shared_ptr<struct_test_struct> tmp_newstruct( new struct_test_struct() );

...and you can simply removed this code entirely: ...并且您可以完全删除以下代码:

    for (unsigned int ui = 0; ui < ui_v_size; ui++) {
        delete v_pointer_TestStruct[ui];
    }

Since the call to v_pointer_TestStruct.clear(); 由于调用v_pointer_TestStruct.clear(); will do this internally from now on. 从现在开始将在内部执行此操作。 This will basically handle all your memory allocations (for this struct at least) for you. 基本上,这将为您处理所有内存分配(至少针对此结构)。

You need to make sure you understand EXACTLY what malloc_stats is returning. 您需要确保完全了解malloc_stats返回什么。

I can't do better than point you at this great post . 我要做的最好的就是告诉你这个好职位 Snippet below.. 下面的代码段

Well, system bytes are, obviously, bytes reserved for the system. 好吧,显然,系统字节是为系统保留的字节。 This means that they're available for the OS and the Rung 2 and below libraries, but not for your programs, which typically run on Rung 4 of the Prerog Ladder. 这意味着它们可用于OS和Rung 2及更低版本的库,但不适用于通常在Prerog Ladder的Rung 4上运行的程序。 In use bytes is, unfortunately, a typo in the library; 不幸的是,使用中的字节是库中的错字。 it should be in use_r_ bytes, and it means bytes left free in the user space (Rung 5 and above) of the current program. 它应该在use_r_个字节中,这表示当前程序的用户空间(行5和更高版本)中剩余的字节。

Executing vector.clear() sets vector.size() == 0, but does not guarantee anything about vector.capacity() . 执行vector.clear()设置vector.size()== 0,但不能保证与vector.capacity() In other words, std::vector is allowed by the Standard to keep its memory allocated, just in case you will fill it with data again. 换句话说,标准允许std :: vector保持其内存分配,以防万一您再次用数据填充它。

To make vector release its memory, use Clear-and-minimize idiom : 要使vector释放其内存,请使用Clear-and-minimize惯用语

vector<struct struct_test_struct *> tmp_empty_vector;
v_pointer_TestStruct.swap(tmp_empty_vector);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM