Как я могу убедиться, что выделенная память std::vector возвращается операционной системе после освобождения?

Код ниже вызывает foo и использует while(1) для наблюдения за использованием памяти. Как я знаю, после печати "finished" var d освобождается, и контейнер STL сам освобождает пространство данных (кучу).

#include <vector>
#include <string>
#include <iostream>

void foo() {
  std::vector<std::string> d(100000000);
  for(int i = 0; i < 100000000; ++i) d[i] = "1,1,3";
  d.resize(0);
  d.shrink_to_fit();
}

int main(int argc, char *argv[])
{
  foo();
  std::cout << "finished" << std::endl;
  while(1) {;}
  return 0; 
}

Но что я заметил (используя htop): память не освобождается обратно в операционную систему. Это просто стенд и реальный код, относящийся к MESOS, который имеет ограничение памяти для каждого процесса.

Я пробовал несколько версий компилятора, таких как g++-4.7.2 g++-4.8.1, clang++ на сервере Linux с glibc 2.15. Более того, я также использую tcmalloc вместо malloc по умолчанию, но он все равно не работает (на машине MAC проблема не возникнет).

В чем проблема? Как я могу убедиться, что память возвращается ОС? Спасибо.


person xunzhang    schedule 26.11.2014    source источник
comment
Кто-то еще может указать это в стандарте, но на основе этого страница delete просто должна освободить память, не указано, что она должна сразу вернуть ее в ОС. Если вы хотите гарантировать это, вам может потребоваться написать свои собственные версии new и delete, которые используют вызовы функций вашей ОС и обеспечивают фактическое возвращение памяти в ОС.   -  person IllusiveBrian    schedule 26.11.2014


Ответы (3)


Как я могу убедиться, что память возвращается ОС?

Вы можете завершить процесс.

В чем проблема?

Там, вероятно, не один. Для программ нормально не возвращать память (хотя Linux возвращает память раньше для некоторых особенно больших выделений). Обычно они используют sbrk или что-то подобное для увеличения доступного им виртуального адресного пространства, но обычно не стоит пытаться вернуть освобожденную память. Это может показаться нелогичным, но это также доказало свою работоспособность для миллионов программ за многие десятилетия, поэтому вам не следует беспокоиться об этом, если у вас нет конкретной ощутимой проблемы. Это не должно вызвать у вас проблем, так как освобожденная память будет повторно использоваться, когда приложение выполняет дальнейшее распределение, поэтому упомянутое вами «ограничение памяти MESOS для каждого процесса» по-прежнему влияет на «высокую отметку» максимального мгновенного использования памяти таким же образом.

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

Также возможно взять на себя ручное управление этим, используя, например. файлы с отображением памяти, но написание таких распределителей и использование контейнеров from Standard - нетривиальная задача... много других вопросов SO о том, как подойти к этой проблеме.

person Tony Delroy    schedule 26.11.2014

Выделение памяти из ОС имеет два недостатка:

  1. Высокие накладные расходы. Системный вызов включает в себя переход в защищенный режим, который занимает гораздо больше времени, чем простой вызов функции, а затем управление памятью для самой ОС, вероятно, является довольно сложным.
  2. Высокая степень детализации. ОС, вероятно, имеет минимальный размер, например 4K. Это много накладных расходов для 6-байтовой строки.

По этим причинам распределитель памяти C++ будет запрашивать у ОС только большие блоки, а затем выделять их части при запросе через new или malloc.

Когда эти фрагменты памяти освобождаются, они помещаются обратно в пул для повторной передачи по следующему запросу. Теперь вполне возможно, что все части большего блока в конечном итоге будут освобождены, но как часто это происходит в реальной жизни? Скорее всего, будет по крайней мере одно выделение на блок, которое останется в течение длительного времени, что не позволит вернуть блок в ОС. И если он возвращается, каковы, по вашему мнению, шансы, что программа развернется и запросит его снова через некоторое время? На практике возвращать блоки в ОС обычно невыгодно. Ваша тестовая программа — это очень искусственный случай, который не стоит оптимизировать.

person Mark Ransom    schedule 26.11.2014

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

person user3344003    schedule 26.11.2014