C ++ неиспользуемая память объектов, содержащих только указатели, как освободить? - PullRequest
1 голос
/ 12 июля 2010

Я только что написал некоторый многопоточный код, который обрабатывает огромные объекты.Даже когда я очищаю все от объекта (не удаляя его), он продолжает поглощать ГБ ОЗУ.К вашему сведению, я воспроизвел проблему в меньшей среде.

Этот код создает структуру и объект, содержащий вектор указателей на структуру.Затем я заполняю объект некоторыми указателями на структуру (созданную с помощью new).Я полагаю, что объект должен иметь только размер указателей, а не размер всех заостренных структур, но когда я запускаю код, размер объекта использует 300 МБ.

Когда я удаляю все элементывектор, а затем очистить вектор, память занята (но не используется сейчас) остается высокой.Кажется, что единственный способ освободить эту память - удалить весь объект, содержащий вектор.Почему вектор так много занимает ОЗУ, если он был только вектором указателя?Как я могу освободить его без необходимости удалять и заново создавать объект?

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 ++ -oa 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 createэти "Arenas" и когда 2 malloc вызываются в один и тот же момент внутри большого объекта malloc, создайте еще одну "Arena", зарезервировав для нее новую карту памяти .. в моей программе у меня наконец-то нет свободного барана с 4 "Arenas"сопоставив более 3 ГБ оперативной памяти каждый, но реально используя менее 100 МБ каждый!поэтому проблема заключалась в отображении памяти (невозможно освободить вручную) и потоковом доступе к памяти, который умножает этот неиспользуемый ОЗУ на эти «арены», поэтому я создаю mutex_lock для всех потоков при доступе к этим объектам, чтобы они сохранялисьта же самая арена без «траты» памяти (отображенной, но не использованной) на несколько арен ..

я надеюсь, что немного объяснил мою проблему и решение .. надеюсь, что это может помочь кому-то еще;) еще раз спасибо, Франческо

----- я все еще тестирую .. я также видел это http://google -perftools.googlecode.com / svn / trunk / doc / tcmalloc.html они точно говорятв чем моя проблема .. "В ptmalloc2 память никогда не может перемещаться с одной арены на другую. Это может привести к огромным потерям пространства." и создать другой распределитель памяти, который должен помочь ..

Ответы [ 4 ]

1 голос
/ 12 июля 2010

Взгляните на Общий указатель Boost .Попробуйте реализовать это в своем коде, что избавит вас от необходимости delete s.В основном, измените ваш вектор на:

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(); теперь будет делать это внутренне.Это будет в основном обрабатывать все ваши выделения памяти (по крайней мере для этой структуры) для вас.

1 голос
/ 12 июля 2010

Вы должны убедиться, что понимаете ТОЧНО, что возвращает malloc_stats.

Я не могу сделать лучше, чем указать на этот великий пост . Фрагмент ниже ..

Ну, системные байты очевидно, байты зарезервированы для системы. Это означает, что они доступно для ОС и библиотек Rung 2 и ниже, но не для ваши программы, которые обычно запускаются на Rung 4 из Prerog Ladder. В использование байтов, к сожалению, является опечаткой в ​​библиотеке; это должно быть в use_r_ bytes, и это означает, что байты оставлены свободными в пространстве пользователя (Rung 5 и выше) текущей программы.

1 голос
/ 12 июля 2010

Без исходного кода для malloc_stats трудно точно знать, о чем вы сообщаете.

Однако следует учитывать, что если вы сообщаете о системных страницах, эти страницы не будут освобождены даже послеВы освобождаете память, используемую C / C ++ (используя delete или free).Причина в том, что когда вы выделяете память с помощью new / malloc, библиотека времени выполнения C запросит сегмент системной памяти, а затем разделит этот блок памяти, чтобы удовлетворить ваш запрос.То же самое верно, когда вы выделяете ОГРОМНЫЙ кусок памяти.C RTL выделит большой блок системной памяти, добавит эту память в список известных блоков доступной памяти C RTL, а затем вернет вам указатель на огромный блок памяти.

Ключ в том, чтодля большинства стандартных распределителей (не всех и, возможно, даже не того, который вы используете), когда вы освобождаете память, эта память не будет возвращена операционной системе, а будет сохранена в списке доступной памяти для будущих новостей и malloc.

Так что, если вы показываете свободную память в терминах системных страниц, вы не увидите, как это число уменьшится, когда вы сделаете свою свободную.

0 голосов
/ 12 июля 2010

Выполнение vector.clear() устанавливает vector.size () == 0, но не гарантирует ничего о vector.capacity(). Другими словами, стандарт позволяет std :: vector сохранять выделенную память, на тот случай, если вы снова заполните ее данными.

Чтобы вектор освободил свою память, используйте идиома «Очистить и свернуть» :

vector<struct struct_test_struct *> tmp_empty_vector;
v_pointer_TestStruct.swap(tmp_empty_vector);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...