Lisp 使用CMUCL的奇怪GC行为

Lisp 使用CMUCL的奇怪GC行为,lisp,common-lisp,Lisp,Common Lisp,为什么这段代码用CMUCL溢出堆?即使我给它400MB内存(setq扩展:*gcs*400000000之间消耗的字节)CMUCL仍然会阻塞它 ; [GC threshold exceeded with 12,012,544 bytes in use. Commencing GC.] ; [GC completed with 188,064 bytes retained and 11,824,480 bytes freed.] ; [GC will next occur when at leas

为什么这段代码用CMUCL溢出堆?即使我给它400MB内存
(setq扩展:*gcs*400000000之间消耗的字节)
CMUCL仍然会阻塞它

; [GC threshold exceeded with 12,012,544 bytes in use.  Commencing GC.]
; [GC completed with 188,064 bytes retained and 11,824,480 bytes freed.]
; [GC will next occur when at least 400,188,064 bytes are in use.]
; [GC threshold exceeded with 400,202,280 bytes in use.  Commencing GC.]
; [GC completed with 207,120 bytes retained and 399,995,160 bytes freed.]
; [GC will next occur when at least 400,207,120 bytes are in use.]
这段代码在CCL和SBCL中运行正常,不过我还没有查看它们的内存使用情况

这是CMUCL中的错误吗??我相信所有这些函数都是尾部递归的

(defun sqrt-iter (guess x)
  (if (good-enough? guess x)
      guess
      (sqrt-iter (improve guess x)
                 x)))

(defun improve (guess x)
  (average guess (/ x guess)))

(defun average (x y)
  (/ (+ x y) 2))

(defun good-enough? (guess x)
  (< (abs (- (* guess guess) x)) 0.001))

(defun mysqrt (x)
  (sqrt-iter 1.0 x))

(defun zint (x acc step)
  (setq num-iter (+ 1 num-iter))
  (if (>= x 10000.0)
      acc
      (zint (+ x step)
           (+ acc (* step (mysqrt x)))
           step)))

(setq num-iter 0)
(format t "result=~A; iterations=~A~%" (zint 0.0 0.0 .001) num-iter)
(quit)

有两个“尾部递归”函数:sqr iter和zint

一般建议

要让编译器优化这些,调试优化级别需要为2或更低

您可以看到编译器是否通过反汇编生成尾部递归代码。使用功能
反汇编

GC调用本身不是问题。大多数实现不在GC上打印任何内容。默认情况下,CMUCL打印它(IIRC)。CMUCL可能会为未优化的代码分配大量的浮点值,这可能会导致大量GC

只有当CMUCL出现堆栈溢出时,您才会看到尾部调用优化不起作用。地面军事系统本身只显示了大量的考虑

因此,要调试您的问题,您首先需要查看代码是否是在启用尾部调用优化的情况下编译的。你可以反汇编代码。另一种选择是在运行时将代码放入调试器,然后查看堆栈回溯。堆栈上不应该有大量的递归调用——它们将被跳转所取代


如果代码是以恒定的堆栈空间运行的,那么您需要查看浮点的分配。然后需要检查代码是否没有分配太多的浮点。

有两个“尾部递归”函数:sqr iter和zint

一般建议

要让编译器优化这些,调试优化级别需要为2或更低

您可以看到编译器是否通过反汇编生成尾部递归代码。使用功能
反汇编

GC调用本身不是问题。大多数实现不在GC上打印任何内容。默认情况下,CMUCL打印它(IIRC)。CMUCL可能会为未优化的代码分配大量的浮点值,这可能会导致大量GC

只有当CMUCL出现堆栈溢出时,您才会看到尾部调用优化不起作用。地面军事系统本身只显示了大量的考虑

因此,要调试您的问题,您首先需要查看代码是否是在启用尾部调用优化的情况下编译的。你可以反汇编代码。另一种选择是在运行时将代码放入调试器,然后查看堆栈回溯。堆栈上不应该有大量的递归调用——它们将被跳转所取代


如果代码是以恒定的堆栈空间运行的,那么您需要查看浮点的分配。您需要检查代码是否分配了太多的浮动。

我认为这取决于设置 ... 这是相关的SBCL

* (declaim (optimize (speed 0) (compilation-speed 0) (safety 3) (debug 3)))
* (defun foo () (bar))
* (defun bar () (foo))
*  (foo)
INFO: Control stack guard page unprotected
Control stack guard page temporarily disabled: proceed with caution

INFO: Control stack guard page reprotected
#<sb-kernel::control-stack-exhausted {1002DBD4D3}> 

我认为这取决于设置 ... 这是相关的SBCL

* (declaim (optimize (speed 0) (compilation-speed 0) (safety 3) (debug 3)))
* (defun foo () (bar))
* (defun bar () (foo))
*  (foo)
INFO: Control stack guard page unprotected
Control stack guard page temporarily disabled: proceed with caution

INFO: Control stack guard page reprotected
#<sb-kernel::control-stack-exhausted {1002DBD4D3}> 
(declaim (optimize (speed 3) (compilation-speed 0) (safety 1) (debug 0)))
(defun foo () (bar))
(defun bar () (foo))
(foo)  ;;; CPU topped out, but no stack issues or garbage collecting