编译、优化和调优

Table of Contents

1 eval-when

简而言之,就是指定Lisp代码在什么阶段执行。执行阶段由参数指定,分别是:

:compile-toplevel 编译成fasl文件时执行
:load-toplevel 会在编译时把body里代码作为top-level来编译,这样在加载fasl时才会生效。
:execute 加载源代码文件时执行

比如调用make-package,必须执行三个时态,才能正常用:

(eval-when (:compile-toplevel :load-toplevel :execute)
  (make-package :hello :use '(cl)))

如果没有指定:execute,那么只能在编译文件、加载fasl文件时正常,而加载源代码文件时就要出错。如果不指定:load-toplevel,在加载fasl文件后也一样找不到:hello这个包,因为make-package部分并没有编译——而只是在编译时执行了一下。

2 编译成可执行文件

SBCl中可以使用sb-ext:save-lisp-and-die函数,其中有几个参数:

:executable 如果为t,保存成stand-alone文件,这样包括SBCL的运行环境也打包进去了
:toplevel 指定运行时的入口函数

例:

(save-lisp-and-die "xxx" :executable t :toplevel 'main)

3 保存image

SBCL

(save-lisp-and-die "文件名"  :executable t :toplevel #'入口函数)

CCL 见:http://ccl.clozure.com/manual/chapter4.9.html#Saving-Applications

默认只是导出内存数据,如果要导出成二进制格式,记得:prepend-kernel t参数。

4 查看内存占用情况

room函数可以统计出内存使用情况,比如在SBCL中:

* (room)

Dynamic space usage is:   53,022,160 bytes.
Immobile space usage is:  14,938,976 bytes (54,256 bytes overhead).
Read-only space usage is:          0 bytes.
Static space usage is:           848 bytes.
Control stack usage is:        1,992 bytes.
Binding stack usage is:          656 bytes.
Control and binding stack usage is for the current thread only.
Garbage collection is currently enabled.

Breakdown for dynamic space:
  13,572,032 bytes for    93,091 simple-vector objects
  12,773,808 bytes for   798,363 cons objects
  10,627,840 bytes for   159,990 instance objects
   2,687,840 bytes for    35,215 simple-array-unsigned-byte-8 objects
  13,491,440 bytes for   253,346 other objects

  53,152,960 bytes for 1,340,005 dynamic objects (space total)

Breakdown for immobile space:
  12,903,808 bytes for 20,327 code objects
   1,234,656 bytes for 25,722 symbol objects
     746,256 bytes for 20,371 other objects

  14,884,720 bytes for 66,420 immobile objects (space total)