2013-03-30 4 views
0

Невозможно выяснить, что происходит неправильно.освобождение памяти для os после использования большого количества unique_ptr - C++

Вот простой код

size_t n_elem = 30000000; //careful! will allocate 1GB with unique_ptr 
vector<unique_ptr<double> > tmp; 
tmp.resize(n_elem); 
for(size_t i=0; i<n_elem; i++){ 
    tmp[i] = unique_ptr<double>(new double((double)i)); 
} 
tmp.clear(); 
//Some answers in Stack overflow seems to suggest this technique to force 
//freeing, but does not seem to work. 
vector<unique_ptr<double> > tmp1; 
tmp.swap(tmp1); 

Когда заканчивается. Системный монитор по-прежнему показывает 948 МБ, как выделено, когда он должен показывать всплеск в использовании памяти, а затем освободить все правильно. Даже если фрагмент заключен в фигурные скобки {...}, чтобы обеспечить область видимости, я не вижу улучшения. Как только память будет выделена, она, похоже, не будет выпущена до конца программы.

Подозревая что-то с вектором, я пробовал приведенный ниже код, но с таким же поведением.

{ 
    size_t n_elem = 30000000; 
    unique_ptr<double>* tmp = new unique_ptr<double>[n_elem]; 
    for(size_t i=0; i<n_elem; i++) 
     tmp[i] = unique_ptr<double>(new double((double)i)); 
    delete[] tmp; 
} 

Однако

size_t n_elem = 30000000; 
double *d_tmp; 
d_tmp = new double[n_elem]; 
for(size_t i=0; i<n_elem; i++) 
{ 
    d_tmp[i] = (double)i; 
} 
delete[] d_tmp; 

Этот код показывает использование памяти растет около 260 МБ, а затем сокращается, как массив будет удален.

Я пробовал использовать класс вместо double и подсчитывал количество раз, когда деструктор вызывается со статической переменной. В обоих случаях деструктор называется правильным числом раз.

Я не могу понять, что не так в том, как я использую unique_ptr и почему он не возвращает память, выделенную ОС после уничтожения. Ссылка cpp, похоже, предполагает, что это должно произойти автоматически, поскольку uniue_ptrs уничтожаются. Как я могу сделать unique_ptr освобожденную память, которую он выделил, и вернуть ее в ОС?

Это произошло на gcc 4.6 с проектом ubuntu 12.04 и qtcreator qt.

+0

Вы создаете два массива unique_ptr и только удаляете один? – yngccc

+0

@yngum, Нет, проблема возникает даже во втором фрагменте кода. Фрагменты запускаются независимо. Первый фрагмент заменяет пустой вектор текущим вектором. – sri

+0

второй фрагмент также создает два уникальных_ptr на каждый элемент – yngccc

ответ

0

немного изменить код

tmp.clear(); // it is not needed 
{ 
    //Some answers in Stack overflow seems to suggest this technique to force 
    //freeing, but does not seem to work. 
    vector<unique_ptr<double> > tmp1; 
    tmp.swap(tmp1); 
} 
// measure memory here 
+0

Спасибо, но, похоже, не работает. Я вижу такое же использование памяти. – sri

0

Попробуйте изменить это:

tmp[i] = unique_ptr<double>(new double((double)i)); 

To:

tmp[i].reset(new double((double)i)); 

Кроме того, я не берусь знать, что вы намерены (или лучше знать), но если то, что вы пытаетесь реплицировать, является динамически распределенным двойным массивом, вам не нужно заставлять его удерживать unique_ptr. Просто используйте прямо вверх vector<double>. В противном случае вы создаете unique_ptr для каждого double, который хотите сохранить. Это не так же, как массив, который постоянно выделяется (таким образом, используя локальность/кеширование). Это, по-видимому, не требует лишних накладных расходов.

+0

Спасибо. Но это тоже не решает проблему. Это всего лишь отдельный случай. Уникальный указатель фактически используется внутри класса для представления на основе дерева, которое может иметь некоторое неизвестное число детей. Я использовал unique_ptr, чтобы не беспокоиться об очистке, когда объекты были уничтожены, но я заметил, что память никогда не падает. Я подозревал код в классе, но оказалось, что я смог воспроизвести то же поведение в этих фрагментах кода. – sri

+0

@sri Вы действительно проверяете код, который вы дали? Или вы используете вместо этого 'unique_ptr ' в своих тестах? Я просто запускал его через valgrind, и он говорит, что утечек памяти нет. В качестве побочного примечания, в ответ на ваш комментарий, я не собираюсь говорить об этом, но похоже, что вы должны иметь возможность использовать 'vector children;' в вашем классе. Я не думаю, что там есть 'unique_ptrs'. –

+0

Я проверяю код образца в вопросе. Я тоже проверял, что утечек памяти нет, однако, похоже, он не освобождает память до os до выхода программы, которая может быть докучливой. Я попробую векторную идею и посмотрю, как это происходит. – sri

0

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

Настоящий вопрос заключается в том, создает ли эта избыточная память проблема; обычно ОС управляет большими рабочими наборами путем замены на диск; неиспользуемые блоки памяти блокируют хранилище резервных копий, но не связывают оперативную память.

Смежные вопросы