Joh*_*ely 13 lisp garbage-collection web-services common-lisp
如果我在Common Lisp映像中托管长时间运行的应用程序(如Web服务器),我应该使用什么策略来管理垃圾收集器?
我假设,默认情况下,垃圾收集器有权花很长时间来整理堆,有时我无法预测.这可能会以我不想要的方式影响特定的浏览器请求.
Common Lisp中有一个方法来控制它吗?也许通过鼓励它以"小而常"的方式工作?
Rai*_*wig 25
几个Lisp实现具有优秀的垃圾收集器.一个特殊问题是Lisp应用程序通常具有较高的小对象分配率(conses,...).
有几点需要考虑.
精确与保守的GC.对于Lisp,我不是保守的GC(Boehm等)的忠实粉丝.保守的GC的一个问题是它们找不到所有垃圾.对于长时间运行的程序而言,这可能是一个问题,并导致碎片而不是回收未使用的内存.精确GC使用Lisp数据的标记信息,可以识别每个对象的每种数据类型.保守的GC是为不使用标记数据的编程语言实现而发明的(C++,...).
复制GC,压缩GC.为了在长时间运行的Lisp中处理内存碎片,压缩和本地化对象的GC可能很有用.当哈希表需要重新哈希时(因为位置发生变化),有时会出现问题.复制GC可能需要更多内存(因为存在内存和内存空间).但是当GC将对象从一个内存空间复制到另一个内存空间时,它会自动使其更紧凑.更高级的GC(比如在Lisp机器上)也可以对对象进行排序并将相同类型的对象分配到彼此附近 - 假设这将加速访问对象.
短暂的GC.这意味着第一个GC阶段专门在主存储器中运行,并从内存管理单元获得一些支持,以识别已更改的内存区域.扫描主存储器比扫描虚拟存储器快,扫描仅更改的存储器区域进一步减少了工作量.当分配了大量对象并迅速变成垃圾时,这会导致GC暂停非常短暂.
世代GC.通常现在的GC都是世代相传的.有一代以上的产品,在少数GC中存活的对象被提升为老一代.通常只有第一代经常使用GC.
调整.例如,LispWorks和Allegro CL的GC有很多调音旋钮.特别是对于长时间运行的应用程序,阅读手册是有意义的,例如调整代数,大小和其他东西.
虚拟内存.GC通过虚拟内存通常很慢.尽可能避免 - 为机器添加更多RAM.
手动内存管理.例如,CL-HTTP Web服务器使用资源进行一些手动内存管理.这些是预先分配的对象池,可以非常快速地重新初始化.Lisp机器正在使用它.它们的典型用途是在流的读缓冲区中.不是每次读取操作都创建新字符串,而是使用可重用缓冲区很有用.
堆栈分配.一些Common Lisp允许堆栈分配一些数据 - 然后让块自动释放内存.这假定在离开块时不再引用存储器.见声明dynamic-extent.
并发GC.通常的Common Lisp实现都没有并发GC并支持并发Lisp线程.一些实现具有并发Lisp线程,但GC将在它工作时停止它们.如果Lisp实现在JVM上运行,如ABCL,那么它可能能够使用JVM并发/并行GC.
分析内存分配.如果您不确定分配发生的位置以及GC的作用,您需要使用分析信息找出它.
如果您的Lisp具有在主存储器中运行的精确世代GC,则很难出现长暂停的问题.例如,Clozure CL(一个免费的Common Lisp实现)在某些平台上具有非常好的GC实现.您希望避免虚拟内存中的内存碎片和垃圾收集.如有必要,使用具有更多主内存的64位Lisp实现.
指针:
从文档中可以看出,LispWorks和Allegro CL有很多用于调优GC的旋钮.
Common Lisp有一些处理实现环境的函数.(ROOM)是一个概述内存使用情况的函数.(ROOM t)提供了更多细节(这里是LispWorks):
CL-USER 2 > (room t)
Generation 0: Total Size 1823K, Allocated 1090K, Free 725K
Segment 2008AAB8: Total Size 507K, Allocated 361K, Free 142K
minimum free space 64K,
Awaiting promotion = 0K, sweeps before promotion =10
Segment 217E7050: Total Size 1315K, Allocated 729K, Free 582K
minimum free space 0K,
Awaiting promotion = 0K, sweeps before promotion =2
Generation 1: Total Size 1397K, Allocated 513K, Free 871K
Segment 20CB9A50: Total Size 68K, Allocated 48K, Free 15K
minimum free space 0K,
Awaiting promotion = 0K, sweeps before promotion =4
Segment 216D7050: Total Size 1088K, Allocated 331K, Free 752K
minimum free space 0K,
Awaiting promotion = 0K, sweeps before promotion =4
Segment 2004E4F8: Total Size 241K, Allocated 133K, Free 103K
minimum free space 0K, static
Generation 2: Total Size 2884K, Allocated 1290K, Free 1585K
Segment 21417050: Total Size 2816K, Allocated 1227K, Free 1584K
minimum free space 0K,
Awaiting promotion = 0K, sweeps before promotion =4
Segment 20DA5DA0: Total Size 68K, Allocated 62K, Free 1K
minimum free space 117K,
Awaiting promotion = 0K, sweeps before promotion =4
Generation 3: Total Size 19373K, Allocated 19232K, Free 128K
Segment 20109A50: Total Size 11968K, Allocated 11963K, Free 0K
minimum free space 3K,
Awaiting promotion = 0K, sweeps before promotion =10
Segment 20DB6E18: Total Size 6528K, Allocated 6396K, Free 128K
minimum free space 0K,
Awaiting promotion = 0K, sweeps before promotion =10
Segment 20CCAAC8: Total Size 876K, Allocated 872K, Free 0K
minimum free space 0K,
Awaiting promotion = 0K, sweeps before promotion =10
Total Size 25792K, Allocated 22127K, Free 3310K
Run Code Online (Sandbox Code Playgroud)