I was able to reduce the problem to a simple test case: Compile and
load the file 'foo.lisp' below in a fresh CMUCL image. Then evaluate
(TEST 1000)
a couple of times. Now do the same thing but with
(TEST 1000 T)
instead. On my machine (CMUCL 18e, Linux x86) in the first case the
output always looks more or less like this [partly snipped for
brevity]:
* (test 1000)
; Evaluation took: ;;; this is LOAD
; 6.88 seconds of real time
; [Run times include 2.2 seconds GC run time]
; 160,029,728 bytes consed.
; [GC threshold exceeded with 52,636,080 bytes in use. Commencing GC.]
; [GC completed with 1,080,872 bytes retained and 51,555,208 bytes freed.]
; [GC will next occur when at least 21,080,872 bytes are in use.]
; Evaluation took: ;;; this is EXT:GC
; 0.2 seconds of real time
NIL
However, in the second case this is what I get from a freshly-started
CMUCL:
* (test 1000 t)
; Evaluation took: ;;; this is LOAD
; 12.59 seconds of real time
; [Run times include 7.24 seconds GC run time]
; 160,037,752 bytes consed.
; [GC threshold exceeded with 160,978,472 bytes in use. Commencing GC.]
; [GC completed with 51,982,504 bytes retained and 108,995,968 bytes freed.]
; [GC will next occur when at least 71,982,504 bytes are in use.]
; Evaluation took: ;;; this is EXT:GC
; 7.94 seconds of real time
NIL
* (test 1000 t)
; Evaluation took: ;;; this is LOAD
; 13.2 seconds of real time
; [Run times include 7.81 seconds GC run time]
; 160,037,752 bytes consed.
; [GC threshold exceeded with 160,976,824 bytes in use. Commencing GC.]
; [GC completed with 156,313,784 bytes retained and 4,663,040 bytes freed.]
; [GC will next occur when at least 176,313,784 bytes are in use.]
; Evaluation took: ;;; this is EXT:GC
; 21.08 seconds of real time
NIL
* (test 1000 t)
; Evaluation took: ;;; this is LOAD
; 13.11 seconds of real time
; [Run times include 7.76 seconds GC run time]
; 0 page faults and
; 160,037,752 bytes consed.
; [GC threshold exceeded with 160,977,032 bytes in use. Commencing GC.]
; [GC completed with 118,550,080 bytes retained and 42,426,952 bytes freed.]
; [GC will next occur when at least 138,550,080 bytes are in use.]
; Evaluation took: ;;; this is EXT:GC
; 16.4 seconds of real time
NIL
Now, for the third test, if I remove the explicit GC calls from
foo.lisp and evaluate (TEST 1000 T) then it takes longer each time I
call it (which is due to GC run time as reported by TIME). After about
four calls I end up with something like
* (test 1000 t)
!!! CMUCL has run out of dynamic heap space. You can control heap size
!!! with the -dynamic-space-size commandline option.
*A2 gc_alloc_new_region failed, nbytes=8.
Generation Boxed Unboxed LB LUB Alloc Waste Trig WP GCs Mem-age
0: 0 0 0 0 0 0 2000000 0 0 0.0000
1: 27218 0 0 0 111462720 22208 2000000 0 0 1.0772
2: 84661 65 0 0 346994672 43024 2000000 84659 0 0.6166
3: 0 0 0 0 0 0 2000000 0 0 0.0000
4: 0 0 0 0 0 0 2000000 0 0 0.0000
5: 0 0 0 0 0 0 2000000 0 0 0.0000
6: 19128 0 0 0 78345016 3272 0 0 0 0.0000
Total bytes alloc=536802408
Does that help? Does this also happen with Solaris?
Cheers,
Edi.
------------------- foo.lisp -------------------------
(defun cons-a-lot (n)
(if (zerop n)
(list 'progn)
`(progn ,(cons-a-lot (1- n)))))
(defun foo-reader (stream char arg)
(declare (ignore arg char))
(cons-a-lot
(* 1000
(loop for char = (peek-char nil stream t nil t)
while (alphanumericp char)
do (read-char stream t nil t)
count t))))
(defun test-gc (&optional verbose)
(let ((ext:*gc-verbose* verbose))
(ext:gc :full t)))
(defun test (n &optional one-form)
(let ((ext:*gc-verbose* nil)
(*readtable* (copy-readtable)))
(set-dispatch-macro-character #\# #\? #'foo-reader)
(with-open-file (s "foo-test.lisp"
:direction :output
:if-exists :supersede)
(when one-form
(format s "(progn~%"))
(loop for i below n
do (format s "#?eeeeeeeeee~%"))
(when one-form
(format s ")~%")))
(test-gc)
(time (load "foo-test.lisp"))
(time (test-gc t))))