处理并最小化 Common Lisp 中的内存使用 (SBCL)
-
22-08-2019 - |
题
我有一个内存不是太多(256Mb)的 VPS,我尝试使用它通过 SBCL+Hunchentoot 进行 Common Lisp 开发,以编写一些简单的 Web 应用程序。大量的内存似乎在没有做任何特别复杂的事情的情况下被使用,并且在提供页面一段时间后,它耗尽了内存,要么疯狂地使用所有交换,要么(如果没有交换)就死掉了。
所以我需要帮助:
- 找出什么在使用所有内存(尤其是图书馆或我)
- 限制 SBCL 允许使用的内存量,以避免大量交换
- 当内存耗尽时干净地处理事情,而不是崩溃(因为它是一个网络应用程序,我希望它继续并尝试清理)。
我认为前两个相当简单,但第三个可能吗?人们如何在 Lisp 中处理内存不足或内存受限的情况?
(另外,我注意到 64 位 SBCL 使用的内存实际上是 32 位的两倍。这是预期的吗?如果可以节省大量内存,我可以运行 32 位版本)
解决方案
要限制 SBCL 的内存使用量,请使用 --dynamic-space-size 选项(例如,sbcl --dynamic-space-size 128
将内存使用限制为 128M)。
要找出谁在使用内存,您可以调用 (room)
(告知正在使用多少内存的函数)在不同时间:在启动时,在加载所有库之后,然后在工作期间(当然,调用 (sb-ext:gc :full t)
房间前不要测量尚未收集的垃圾)。
此外,还可以使用 SBCL Profiler 来测量内存分配。
其他提示
找出使用所有内存的方法(如果是库或我,尤其是我)
Attila Lendvai 有一些特定于 SBCL 的代码来查找分配的对象来自何处。参考 http://article.gmane.org/gmane.lisp.steel-bank.devel/12903 如果需要的话,给他写一封私人邮件。
请务必尝试其他实现,最好使用精确的 GC(如 Clozure CL),以确保它不是特定于实现的泄漏。
限制允许SBCL使用的内存量,以避免大量交换
其他人已经回答了。
当内存耗尽而不是崩溃时,请干净地处理内容(因为这是一个网络应用程序,我希望它继续下去并尝试清理)。
256MB 有点紧张,但无论如何:安排一个循环(可能是 1 秒)定时线程来检查剩余的可用空间。如果可用空间小于 X,则使用 exec() 将当前 SBCL 进程映像替换为新进程映像。
如果没有任何类型声明,我预计 64 位 Lisp 占用的空间是 32 位 Lisp 的两倍。即使是普通(小)int 也会使用 64 位内存块。我不认为它会使用少于机器字,除非你声明它。
我无法帮助解决#2 和#3,但如果您弄清楚#1,我怀疑这不会是问题。我已经看到 SBCL/Hunchentoot 实例运行了很长时间。如果我使用了过多的内存,通常是我自己的错。:-)
我不会对使用两倍内存的 64 位 SBCL 感到惊讶,因为它可能会使用 64 位单元而不是 32 位单元,但在没有实际检查的情况下无法确定。
使内存停留时间超过预期的典型因素是不再有用的引用,但它们仍然具有到根分配集的路径(我发现,散列表是让这些东西停留的好方法)。您可以尝试在代码中散布对 GC 的显式调用,并确保(尽可能)不要将内容存储在全局变量中。