Это занимает время для освобождения памяти?

У меня есть программа C++, которая, во время выполнения, выделит о 3-8Gb из памяти для хранения хеш-таблицы (я использую tr1/unordered_map), и различные другие структуры данных.

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

Например, в самом конце моей основной функции я имею

std::cout << "End of execution" << endl;

Но осуществление моей программы пойдет что-то как

. $/программир
действительно наполнить...
Конец выполнения
[длинная пауза, возможно, 2 минут]
$ - возвращается к оболочке

Это - ожидаемое поведение, или я делаю что-то не так?

Я предполагаю, что программа освобождает память в конце. Но, коммерческое применение, которое использует большие объемы памяти (такие как фотошоп) не показывает эту паузу при закрытии приложения.

Советуйте :)

Править: Самая большая структура данных unordered_map включенный с a string и хранилища a list из integers.

Я использую g++ -O2 на Linux компьютер, который я использую, имеет 128 ГБ памяти (с большей частью из этого свободного). Существует несколько гигантских объектов

Решение: Я закончил тем, что избавился от хеш-таблицы, так как это было почти полно так или иначе. Это решило мою проблему.

13
задан jm1234567890 10 April 2010 в 19:07
поделиться

14 ответов

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

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

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

Это можно сделать, напрямую вызвав функцию libc exit (3) или _exit (2) операционной системы. Тем не менее, я был бы очень осторожен , чтобы убедиться, что это не приводит к короткому замыканию каких-либо других (важных) чисток, которые может выполнять код деструктора C ++. И то, что это делает или не делает, сильно зависит от системы (операционная система, компилятор, libc, API, которые вы использовали, ...).

13
ответ дан 1 December 2019 в 17:27
поделиться

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

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

0
ответ дан 1 December 2019 в 17:27
поделиться

Вы можете избежать вызова free для объекта, используя вызов деструктора my_object-> ~ my_class () вместо delete my_object . Вы можете избежать free для всех объектов класса, переопределив и аннулировав оператор delete (void *) {} внутри класса. Производные классы с виртуальными деструкторами унаследуют этот delete , в противном случае вы можете скопировать-вставить (или, возможно, , используя base :: operator delete; ).

Это намного чище, чем вызов exit . Только убедитесь, что вам не нужно возвращать эту память!

1
ответ дан 1 December 2019 в 17:27
поделиться

Я не могу себе представить, как вы бы использовали достаточно памяти, чтобы это имело значение, но одним из способов, которым я ускорил программу, было использование boost :: object_pool для выделения памяти для двоичного дерева. Основным преимуществом для меня было то, что я мог просто поместить пул объектов в качестве переменной-члена дерева, и когда дерево выходило за пределы области видимости или было удалено, пул объектов удалялся сразу (что позволяло мне не использовать рекурсивный деконструктор для узлов). object_pool действительно вызывает деконтрукторы всех своих объектов при выходе. Я не уверен, обрабатывает ли он пустые деконтракторы особым образом или нет.

Если вам не нужен ваш распределитель для вызова конструктора, вы также можете использовать boost :: pool , который, я думаю, может освободить место быстрее, потому что ему вообще не нужно вызывать деконструкторы, а просто удалил кусок памяти в одном free () .

5
ответ дан 1 December 2019 в 17:27
поделиться

время, вероятно, тратится не на освобождение памяти, а на вызов всех деструкторов. Вы можете предоставить свой собственный распределитель, который не вызывает деструктор (если объект на карте не нужно разрушать, а только освобождать).

Также обратите внимание на другой вопрос: Распределители, соответствующие STL C ++

4
ответ дан 1 December 2019 в 17:27
поделиться

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

3
ответ дан 1 December 2019 в 17:27
поделиться

Да, освобождение памяти может занять некоторое время, а также, возможно, у вас есть код, выполняющийся как вызываемые деструкторы. Photoshop не использует 3-8 ГБ памяти.

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

8
ответ дан 1 December 2019 в 17:27
поделиться

Я бы порекомендовал (как и некоторые другие) простое принудительное завершение процесса, если вы уверены, что вам нечего делать, кроме как освободить память ( например, нет файлового ввода-вывода и тому подобное).

Дело в том, что когда вы освобождаете память, обычно она фактически не возвращается в ОС - она ​​хранится в списке для перераспределения, и это, очевидно, медленно. Однако, если вы завершите процесс, ОС сразу же освободит всю вашу память, что должно быть значительно быстрее. Однако, как говорили другие, если у вас есть какие-либо деструкторы, которые необходимо запустить, вы должны убедиться, что они запускаются до принудительного вызова exit () или ExitProcess или любой такой функции.

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

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

0
ответ дан 1 December 2019 в 17:27
поделиться

Объекты в памяти организованы в куче. Они не удаляются сразу, они удаляются по одному, а стоимость удаления объекта составляет O (log n). Чтобы их освободить, нужно много времени.

Тогда ответ: да, это занимает так много времени.

1
ответ дан 1 December 2019 в 17:27
поделиться

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

ищут глобальные объекты и исследуют их деструкторы.

2
ответ дан 1 December 2019 в 17:27
поделиться

Извините, но это ужасный вопрос. Вам необходимо показать исходный код с указанием конкретных алгоритмов и структур данных, которые вы используете.

Это может быть перераспределение, но это просто дикая догадка. Что делают ваши деструкторы? Может быть, листает как сумасшедший. Тот факт, что ваше приложение выделяет X объема памяти, не означает, что оно его получит. Скорее всего, это будет подкачка виртуальной памяти. В зависимости от специфики вашего приложения и ОС, у вас может быть много страниц с ошибками.

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

Я был бы очень удивлен, если действительно все прошедшее время в конце произошло исключительно из-за отмены распределения.

Запустите vmstat и iostat, как только получите сообщение «конец», и ищите любые признаки того, что ввод-вывод идет как банан.

1
ответ дан 1 December 2019 в 17:27
поделиться

Для освобождения памяти может потребоваться время - структуры данных обновляются. Сколько времени зависит от используемого распределителя.

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

2 минуты звучат как много времени - возможно, вы захотите выполнить код очистки в отладчике (или использовать профилировщик, если это удобнее), чтобы увидеть, что на самом деле занимает все время.

4
ответ дан 1 December 2019 в 17:27
поделиться

(Я начал это как ответ на ndim, но получилось слишком долго)

Как ndim уже писал, завершение может занять много времени.
Вероятные причины:

  • у вас много распределений, и части кучи выгружены на диск.
  • длительно выполняющиеся деструкторы
  • другие процедуры atexit
  • Очистка, специфичная для ОС, например, уведомление DLL о завершении потока и процесса в Windows (не знаю, что именно происходит в Linux).

exit здесь не наихудший обходной путь, однако реальное поведение зависит от системы. например exit в WIndows / MSVC CRT запустит процедуры глобальных деструкторов / atexit , а затем вызовет ExitProcess, который закрывает дескрипторы (но не обязательно сбрасывает их - по крайней мере, это не гарантируется).

Недостатки: деструкторы объектов, выделенных кучей, не запускаются - если вы полагаетесь на них (например, для сохранения состояния), вы - тост. Кроме того, становится намного сложнее отслеживать реальные утечки памяти.

Найдите причину Вы должны сначала проанализировать происходящее.

например. Освободив вручную корневые объекты, которые все еще выделены, вы можете отделить время освобождения от очистки других процессов. Согласно вашему описанию, вероятная причина - память, но не единственная. Также возможна некоторая взаимоблокировка кода очистки до того, как он достигнет тайм-аута. Статистика мониторинга (например, ЦП / активность подкачки / использование диска) может дать подсказки.

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

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

7
ответ дан 1 December 2019 в 17:27
поделиться

Конечно, это возможно.

Около 7 лет назад у меня была аналогичная проблема в проекте, там было намного меньше памяти, но компьютеры тоже, я полагаю, работали медленнее.

В конце концов, нам пришлось бесплатно взглянуть на язык сборки, чтобы понять, почему он такой медленный, и казалось, что он по существу хранит освобожденные блоки в связанном списке, чтобы их можно было перераспределить, а также сканировал этот список ищу блоки для объединения. Сканирование списка было операцией O (n), но освобождение n объектов превратило его в O (n ^ 2)

. Наши тестовые данные заняли около 5 секунд, чтобы освободить память, но у некоторых клиентов было примерно в 10 раз больше данных, чем мы все использовали, и на завершение работы программы в их системах уходило 5-10 минут.

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

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

6
ответ дан 1 December 2019 в 17:27
поделиться
Другие вопросы по тегам:

Похожие вопросы: