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

Почему gc() не освобождает память?

Я запускаю симуляции на Windows 64bit-computer с оперативной памятью 64 ГБ. Использование памяти достигает 55%, и после законченного симулятора я удаляю все объекты в рабочем пространстве rm(list=ls()), а затем double gc().

Я предположил, что это освободит достаточно памяти для следующего симулятора, но на самом деле использование памяти падает всего на 1%. Консультируя множество разных форумов, я не смог найти удовлетворительного объяснения, только смутные комментарии, такие как:

"В зависимости от вашей операционной системы освобожденная память может не возвращаться в операционную систему, а хранится в пространстве процесса".

Я хотел бы найти информацию о:

  • 1) какая ОС и в каких условиях освобожденная память не возвращается ОС, а
  • 2), если есть какое-либо другое средство, кроме закрытия R, и запустить его снова для следующего запуска моделирования?
4b9b3361

Ответ 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'