Подтвердить что ты не робот

Огромный std::vector <std:: vector> не освобождает всю память при уничтожении

При использовании очень большого вектора векторов мы обнаружили, что часть памяти не выпущена.

#include <iostream>
#include <vector>
#include <unistd.h>

void foo()
{
    std::vector<std::vector<unsigned int> > voxelToPixel;
    unsigned int numElem = 1<<27;
    voxelToPixel.resize( numElem );

    for (unsigned int idx=0; idx < numElem; idx++)
        voxelToPixel.at(idx).push_back(idx);

}

int main()
{
    foo();
    std::cout << "End" << std::endl;
    sleep(30);
    return 0;
}

Это оставляет около 4 ГБ памяти, висящей до тех пор, пока процесс не завершится.

Если мы изменим строку for на

for (unsigned int idx=0; idx < numElem; idx++)
    voxelToPixel.at(0).push_back(idx);

память освобождается.

Использование gcc-4.8 на Linux-машине. Мы использовали htop для отслеживания использования памяти на компьютере со 100 ГБ ОЗУ. Для запуска кода вам понадобится около 8 ГБ оперативной памяти. Можете ли вы воспроизвести проблему? Любые идеи о том, почему это происходит?

EDIT: Мы видели, что этого не происходит на Mac (с помощью gcc или clang). Кроме того, в linux память освобождается, если мы вызываем foo два раза (но повторимся в третий раз).

4b9b3361

Ответ 1

Малые распределения (по умолчанию, по-моему, до 128 Кбайт) управляются кучей в процессе и не возвращаются в ОС при их освобождении; они возвращаются в кучу для повторного использования в процессе. Большие выделения поступают непосредственно из ОС (вызывая mmap) и возвращаются в ОС при освобождении.

В вашем первом примере каждому вектору требуется выделить достаточно места для одного int. У вас есть сто миллионов небольших распределений, ни одна из которых не будет возвращена ОС.

Во втором примере, когда вектор растет, он будет делать много распределений различных размеров. Некоторые из них меньше порога mmap, они останутся в памяти процесса; но, поскольку вы делаете это только с одним вектором, это не будет огромной суммой. Если вы должны были использовать resize или reserve для выделения всей памяти для каждого вектора перед ее заполнением, вы должны обнаружить, что вся память возвращается в ОС.