编译、优化和调优

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)