unordered_map: clear() не освобождает кучу при clear()

Я использую unordered_map с помощью g++ 4.9.2 на Solaris 10, но неожиданно обнаружил, что clear() не освобождает кучу. Вот пример кода:

#include <iostream>
#include <unordered_map>

int main ()
{
  std::unordered_map<long long, long long> mymap;
  mymap.rehash(200000);
  getchar();
  for (int i = 0; i < 2000000; i++) {
    mymap[i] = i*i;
  }
  std::cout << "current bucket_count: " << mymap.bucket_count() << std::endl;
  std::cout << "current size: " << mymap.size() << std::endl;
  getchar();
  mymap.clear();
  std::cout << "current bucket_count: " << mymap.bucket_count() << std::endl;
  std::cout << "current size: " << mymap.size() << std::endl;
  getchar();
  return 0;
}

Я наблюдаю размер кучи для программы, когда программа ожидает getchar(). И вот снимок кучи, найденный через pmap -x <PID> | grep heap

1. While waiting on 1st getchar(): `0002C000     792     792     792       - rwx--    [ heap ]`

2. After 1st getchar(): it prints:

    current bucket_count: 3439651
    current size: 2000000
Heap shows while waiting on 2nd getchar():

    0002C000    3920    3920    3920       - rwx--    [ heap ]
    00400000   73728   72272   72272       - rwx--    [ heap ]

3. After 2nd getchar(): it prints:

    current bucket_count: 3439651
    current size: 0
Heap shows while waiting on 2nd getchar():
0002C000    3920    3920    3920       - rwx--    [ heap ]
00400000   73728   72272   72272       - rwx--    [ heap ]

Это показывает (шаг 3), что clear() не влияет на кучу. Хотя в документации сказано,

std::unordered_map::clear
void clear() noexcept;
Clear content
All the elements in the unordered_map container are dropped: their destructors are called, and they are removed from the container, leaving it with a size of 0.

Но мой счетчик кучи не отражает этого. Есть ли другой способ освободить кучу, занятую объектом unordered_map? Или я должен использовать что-то еще? Подскажите, пожалуйста, как освободить память из unordered_map?


person Dr. Debasish Jana    schedule 01.03.2017    source источник
comment
Цитата из документации ничего не говорит об освобождении памяти, используемой внутри карты, только о том, что карта станет пустой. Что, очевидно, так и есть (поскольку вы печатаете размер как ноль).   -  person Some programmer dude    schedule 01.03.2017
comment
Я думаю, вы должны понимать, что существует разница между размером и емкостью. Он не освобождает базовую структуру данных, даже если освобождает память, используемую для содержащихся элементов. Когда вы вызываете clear, он, вероятно, вызывает деструкторы и устанавливает некоторую переменную размера в 0, но не освобождает память, удерживаемую контейнером.   -  person Paul Rooney    schedule 01.03.2017
comment
Получив память от операционной системы для возврата в ответ на вызовы new, библиотека времени выполнения C++ не освободит ее, пока процесс не завершится.   -  person Martin Bonner supports Monica    schedule 01.03.2017


Ответы (3)


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

Если вы действительно не освободите память карты, вам нужно уничтожить весь объект. Или вы можете попробовать позвонить void reserve( size_type count ); с нулем. (я не пробовал)

person elanius    schedule 01.03.2017
comment
резерв (0) может не работать, потому что он не является обязательным, а значение резерва будет меньше, чем емкость. - person Swtsvn; 21.09.2017

Память не освобождается, потому что предполагается, что карта будет использоваться до тех пор, пока она не выйдет из области действия или не будет удалена. Для этого разумного варианта использования по умолчанию перераспределение вызовет ненужные накладные расходы. Мои предложения:

  • Если он действительно больше не нужен, ограничьте его область действия там, где вам это нужно, соответственно используйте интеллектуальные указатели для карты с соответствующей областью действия.
  • Если она вам по-прежнему нужна, но ненадолго или только с гораздо меньшим количеством элементов, swap ее с пустой временной картой (которая потом будет удалена).
  • Явно вызовите деструктор и заново создайте новую карту на месте.
person Peter - Reinstate Monica    schedule 01.03.2017

unordered_map: clear() не освобождает кучу при clear()

Стандарт C++ не требует clear для освобождения памяти.

Но мой счетчик кучи не отражает этого.

В документации ничего не упоминается о куче. Были вызваны деструкторы элементов, и, как вы подтвердили, размер равен 0. Если вы добавите новые элементы, они могут повторно использовать память, которую использовали ранее очищенные элементы.

Есть ли другой способ освободить кучу, занятую объектом unordered_map?

Уничтожение карты определенно освободит всю ее память.

mymap.rehash(0) тоже может работать.

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

В C++ нет стандартного способа сделать это, но Linux предоставляет функцию malloc_trim, которая пытается освободить освобожденную память из верхней части кучи для ОС.

person eerorika    schedule 01.03.2017