Преодоление и минимизация использования памяти в Common Lisp (SBCL)
У меня есть VPS с не очень большой памятью (256 Мб), которую я пытаюсь использовать для разработки Common Lisp с SBCL + Hunchentoot для написания простых веб-приложений. Похоже, что большой объем памяти используется, не делая ничего особо сложного, и через некоторое время на страницах обслуживания у него заканчивается память, и либо он сходит с ума, используя все свопы, либо (если нет свопа) просто умирает.
Мне нужна помощь:
- Узнайте, что использует вся память (если это библиотеки или я, особенно)
- Ограничьте объем памяти, который SBCL разрешен для использования, чтобы избежать массового количества подкачки
- Обрабатывайте вещи чисто, когда память заканчивается, а не сбой (поскольку это веб-приложение, которое я хочу, чтобы оно продолжалось и пыталось очистить).
Я предполагаю, что первые два достаточно просты, но третий даже возможен?
Как люди справляются с проблемами памяти или ограничения памяти в Lisp?
(Кроме того, я отмечаю, что 64-разрядный SBCL, по-видимому, использует буквально вдвое больший объем памяти, чем 32-разрядный. Является ли это ожидаемым? Я могу запустить 32-разрядную версию, если она сэкономит много памяти)
Ответы
Ответ 1
Чтобы ограничить использование памяти SBCL, используйте параметр --dynamic-space-size (например, sbcl --dynamic-space-size 128
ограничит использование памяти до 128M).
Чтобы узнать, кто использует память, вы можете вызвать (room)
(функция, которая сообщает, сколько памяти используется) в разное время: при запуске, после загрузки всех библиотек, а затем во время работы (из курса, звоните (sb-ext:gc :full t)
перед комнатой, чтобы не измерить мусор, который еще не был собран).
Кроме того, для измерения распределения памяти можно использовать SBCL Profiler.
Ответ 2
Узнайте, что использует всю память (если это библиотеки или я, особенно)
У Attila Lendvai есть код, специфичный для SBCL, чтобы узнать, откуда взялись выделенные объекты. Обратитесь к http://article.gmane.org/gmane.lisp.steel-bank.devel/12903 и напишите ему личное письмо, если необходимо.
Обязательно попробуйте другую реализацию, желательно с точным GC (например, Clozure CL), чтобы убедиться, что это не утечка, специфичная для реализации.
Ограничьте объем памяти, который SBCL разрешено использовать, чтобы избежать массовых количества подкачки
Уже ответили другие.
Четко обрабатывайте вещи, когда выполняется память а не сбой (поскольку это веб-приложение, которое я хочу, чтобы оно продолжалось и попробуйте очистить).
256 Мб является жестким, но в любом случае: планируйте повторяющийся (возможно, 1 с) тайм-поток, который проверяет оставшееся свободное пространство. Если свободное пространство меньше X, используйте exec() для замены текущего образа процесса SBCL на новый.
Ответ 3
Если у вас нет объявлений типов, я бы ожидал, что 64-разрядный Lisp займет в два раза больше пространства 32-разрядного. Даже простой (маленький) int будет использовать 64-битный кусок памяти. Я не думаю, что он будет использовать меньше машинного слова, если вы не объявите его.
Я не могу помочь С# 2 и # 3, но если вы поймете №1, я подозреваю, что это не проблема. Я видел экземпляры SBCL/Hunchentoot на протяжении веков. Если я использую возмутительный объем памяти, это обычно моя собственная ошибка.: -)
Ответ 4
Я бы не удивился 64-разрядному SBCL, использующему в два раза больше, поскольку он, вероятно, будет использовать 64-битную ячейку, а не 32-битную, но не мог точно сказать, не проверив.
Типичные вещи, которые удерживают память в ожидании дольше, чем ожидалось, - это ненужные ссылки, которые все еще имеют путь к набору корневого распределения (хэш-таблицы - это, я считаю, хороший способ позволить этим вещам задерживаться). Вы можете попробовать вставлять явные вызовы GC в свой код и следить за тем, чтобы (насколько это возможно) не хранить вещи в глобальных переменных.