在 Common Lisp (SBCL) 中处理和最小化内存使用

Posted

技术标签:

【中文标题】在 Common Lisp (SBCL) 中处理和最小化内存使用【英文标题】:Coping with, and minimizing, memory usage in Common Lisp (SBCL) 【发布时间】:2010-10-17 01:39:59 【问题描述】:

我有一个内存不大的 VPS (256Mb),我正在尝试将其用于使用 SBCL+Hunchentoot 进行 Common Lisp 开发,以编写一些简单的 Web 应用程序。大量内存似乎在没有做任何特别复杂的事情的情况下被使用,并且在服务页面一段时间后它耗尽内存并且使用所有交换变得疯狂或者(如果没有交换)就死了。

所以我需要帮助:

找出正在使用所有内存的内容(尤其是库或我) 限制 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 来测量内存分配。

【讨论】:

您能添加一个链接到有关 SBCL 分析器的内容吗? :) 在sbcl.org/manual/Deterministic-Profiler.html的SBCL手册中有profiler的描述【参考方案2】:

找出正在使用所有内存的内容 (尤其是图书馆或我)

Attila Lendvai 有一些特定于 SBCL 的代码来找出分配对象的来源。如果需要,请参考http://article.gmane.org/gmane.lisp.steel-bank.devel/12903 并给他写一封私人邮件。

请务必尝试其他实现,最好使用精确的 GC(如 Clozure CL),以确保它不是特定于实现的泄漏。

限制SBCL的内存量 允许使用,避免大量使用 交换数量

其他人已经回答了。

当内存运行时干净地处理事情 出来,而不是崩溃(因为它是 我希望它继续运行的网络应用程序 尝试清理)。

256MB 很紧,但无论如何:安排一个重复的(可能是 1 秒)定时线程来检查剩余的可用空间。如果可用空间小于 X,则使用 exec() 将当前的 SBCL 进程映像替换为新的。

【讨论】:

【参考方案3】:

如果您没有任何类型声明,我预计 64 位 Lisp 占用的空间是 32 位的两倍。即使是普通的(小)int 也会使用 64 位的内存块。我认为它不会少于一个机器词,除非你声明它。

我对#2 和#3 无能为力,但如果你弄清楚#1,我怀疑它不会有问题。我已经看到 SBCL/Hunchentoot 实例运行了很长时间。如果我使用了大量的内存,通常是我自己的错。 :-)

【讨论】:

【参考方案4】:

我不会对使用两倍内存的 64 位 SBCL 感到惊讶,因为它可能会使用 64 位单元而不是 32 位单元,但如果不进行实际检查就无法确定。

使内存停留时间超过预期的典型事情是不再有用的引用,它们仍然具有通往根分配集的路径(我发现哈希表是让这些事情持续存在的好方法)。您可以尝试在代码中散布对 GC 的显式调用,并确保(尽可能)不将内容存储在全局变量中。

【讨论】:

以上是关于在 Common Lisp (SBCL) 中处理和最小化内存使用的主要内容,如果未能解决你的问题,请参考以下文章

在 Common Lisp 中使用 iterate 包的正确方法

如何理解这个 Common Lisp 包的行为?

重新定义已删除的包(Common Lisp)

为啥这个 Common Lisp 宏不起作用?书上的答题卡错了吗?

SLIME 和 SWANK 在 MIPS 架构上失败

SBCL:构建一个独立的可执行文件