Почему gc() не освобождает память?
Я запускаю симуляции на Windows 64bit-computer с оперативной памятью 64 ГБ. Использование памяти достигает 55%, и после законченного симулятора я удаляю все объекты в рабочем пространстве rm(list=ls())
, а затем double gc()
.
Я предположил, что это освободит достаточно памяти для следующего симулятора, но на самом деле использование памяти падает всего на 1%. Консультируя множество разных форумов, я не смог найти удовлетворительного объяснения, только смутные комментарии, такие как:
"В зависимости от вашей операционной системы освобожденная память может не возвращаться в операционную систему, а хранится в пространстве процесса".
Я хотел бы найти информацию о:
- 1) какая ОС и в каких условиях освобожденная память не возвращается ОС, а
- 2), если есть какое-либо другое средство, кроме закрытия R, и запустить его снова для следующего запуска моделирования?
Ответы
Ответ 1
Как вы проверяете использование памяти? Обычно виртуальная машина выделяет часть памяти, которую она использует для хранения своих данных. Некоторые из выделенных могут быть неиспользованными и помечены как бесплатные. Что GC делает, это поиск данных, которые не упоминаются нигде и маркировка соответствующих кусков памяти как неиспользуемых, это не означает, что эта память освобождается в ОС. Тем не менее с точки зрения VM теперь имеется больше свободной памяти, которая может использоваться для дальнейших вычислений.
Как выяснили другие, вы столкнулись с ошибками памяти? Если нет, то не о чем беспокоиться.
EDIT:
Это и this должно быть достаточно, чтобы понять, как распределение памяти и сборка мусора работают в R.
Из первого документа:
Иногда предпринимается попытка освободить неиспользуемые страницы операционная система. Когда страницы освобождаются, количество свободных узлов равный R_MaxKeepFrac раз количество выделенных узлов для каждого класс сохраняется. Страницы, которые не нужны для выполнения этого требования, выпущенный. Попытка освобождения страниц производится каждый R_PageReleaseFreq уровень 1 или коллекций уровня 2.
EDIT2:
Чтобы увидеть используемую память, попробуйте запустить gc() с подробным значением TRUE:
gc(verbose=T)
Здесь результат с массивом из 10 000 000 целых чисел в памяти:
Garbage collection 9 = 1+0+8 (level 2) ...
10.7 Mbytes of cons cells used (49%)
40.6 Mbytes of vectors used (72%)
used (Mb) gc trigger (Mb) max used (Mb)
Ncells 198838 10.7 407500 21.8 350000 18.7
Vcells 5311050 40.6 7421749 56.7 5311504 40.6
И вот после отбрасывания ссылки на него:
Garbage collection 10 = 1+0+9 (level 2) ...
10.7 Mbytes of cons cells used (49%)
2.4 Mbytes of vectors used (5%)
used (Mb) gc trigger (Mb) max used (Mb)
Ncells 198821 10.7 407500 21.8 350000 18.7
Vcells 310987 2.4 5937399 45.3 5311504 40.6
Как вы можете видеть, память, используемая Vcells, упала с 40,6 МБ до 2,4 МБ.
Ответ 2
Сборщик мусора R
несовершенен следующим (не очень) тонким способом: он не перемещает объекты (т.е. Не сжимает память) из-за того, как он взаимодействует с библиотеками C
. (Некоторые другие языки/реализации тоже страдают от этого, но другим, несмотря на то, что им также приходится взаимодействовать с C
, удается создать компактный GC поколений, который не страдает от этой проблемы).
Это означает, что если вы по очереди выделяете небольшие порции памяти, которые затем отбрасываются, а большие порции для более постоянных объектов (это обычная ситуация при обработке строк/регулярных выражений), то ваша память становится фрагментированной, и сборщик мусора ничего не может с этим поделать это: память освобождается, но не может быть повторно использована, потому что свободные фрагменты слишком короткие.
Единственный способ решить эту проблему - сохранить нужные объекты, перезапустить R
и перезагрузить объекты.
Поскольку вы выполняете rm(list=ls())
, т.е. Вам не нужны никакие объекты, вам не нужно ничего сохранять и перезагружать, так что в вашем случае решение именно то, чего вы хотите избежать - перезапуск R
,
PS. Сборка мусора - весьма нетривиальная тема. Например, Руби использовал 5 (!) Различных алгоритмов GC за 20 лет. Java GC не отстой, потому что Sun/Oracle и IBM потратили много лет программиста на свои соответствующие реализации GC. С другой стороны, R и Python имеют паршивый GC - потому что никто не удосужился потратить необходимые человеческие годы - и они довольно популярны. Это хуже-лучше для тебя.
PPS. Связанный: R: исчерпание памяти с помощью 'strsplit'