Heap exhausted, large arrays
Affects | Status | Importance | Assigned to | Milestone | |
---|---|---|---|---|---|
SBCL |
New
|
Undecided
|
Unassigned |
Bug Description
I'm finding that when I do a lot of calcs with big arrays, I'm getting a heap exhausted & sbcl falls into the ldb.
Here's some test code that causes it to happen fairly reliably. Call it foo.lisp:
(eval-when (:compile-toplevel)
(declaim (optimize (speed 3) (safety 1) (space 0) (debug 0))))
(defun rseq (a b num)
"Args: (a b num)
Returns a list of NUM equally spaced points starting at A and ending at B."
(declare (type number a b)
(type (integer 0 1000000000) num)
(values cons))
(let ((d (/ (float (- b a)) (1- num))))
(loop for i upto (1- num) collect (+ a (* i d)))))
(defun v4* (a b)
(declare (type (simple-array double-float (*)) a b))
(assert (eq (length a) (length b)) (a b)
"Sequence arguments are not of the same length.")
(map '(simple-array double-float (*)) #'* a b))
(defun testv4 (n m)
(declare (type (integer 1 10000000) n m))
(let ((v1 (coerce (rseq 0d0 (1- m) m) '(vector double-float)))
(v2 (coerce (rseq 0d0 .1d0 m) '(vector double-float))))
(time (progn (dotimes (i n)
(setq v1 (v4* v1 v2)))))
(reduce #'+ v1)))
In SBCL, then do:
(load (compile-file "foo"))
and keep doing:
(testv4 100 1000000)
After enough iterations, I eventually get:
* Heap exhausted during garbage collection: 0 bytes available, 16 requested.
Gen StaPg UbSta LaSta LUbSt Boxed Unboxed LB LUB !move Alloc Waste Trig WP GCs Mem-age
0: 24608 0 23685 0 1483 87 0 245 0 59388320 85600 24487962 0 1 0.0000
1: 32737 32767 0 0 2284 2252 0 735 747 172492624 227504 10737418 1527 0 0.8588
2: 30066 30418 0 0 3718 3699 0 1470 1243 290840336 368880 59301018 3700 1 0.6286
3: 9440 14867 0 0 3567 3545 0 1960 1492 296794944 476352 145342330 3545 1 0.4535
4: 19629 19628 0 0 2938 2689 0 735 753 208150592 319424 2000000 2920 0 0.0000
5: 0 0 0 0 0 0 0 0 0 0 0 2000000 0 0 0.0000
6: 0 0 0 0 1196 165 0 0 0 44597248 0 2000000 1116 0 0.0000
Total bytes allocated = 1072264064
Dynamic-
GC control variables:
*GC-INHIBIT* = true
*GC-PENDING* = true
*STOP-
fatal error encountered in SBCL pid 8253(tid 140737353930560):
Heap exhausted, game over.
Welcome to LDB, a low-level debugger for the Lisp runtime environment.
ldb>
I realize the above code creates a log of garbage, but I'm not holding onto it. Shouldn't the GC reclaim it?
Details:
In stock Linux Mint 17.1 sbcl:
~/lisp/cls$ sbcl --version
SBCL 1.1.14.debian
But I also reporduced
~/lisp/cls$ uname -a
Linux hjstein-
~/lisp/cls$ sbcl
This is SBCL 1.1.14.debian, an implementation of ANSI Common Lisp.
More information about SBCL is available at <http://
SBCL is free software, provided as is, with absolutely no warranty.
It is mostly in the public domain; some portions are provided under
BSD-style licenses. See the CREDITS and COPYING files in the
distribution for more information.
* *features*
(:QUICKLISP :SB-BSD-
:NON-BASE-
:ASH-RIGHT-VOPS :C-STACK-
:COMPLEX-
:IEEE-
:LITTLE-ENDIAN :MEMORY-
:OS-PROVIDES-
:OS-PROVIDES-POLL :OS-PROVIDES-PUTWC :OS-PROVIDES-
:PACKAGE-
:SB-EVAL :SB-FUTEX :SB-LDB :SB-PACKAGE-LOCKS :SB-SIMD-PACK
:SB-SOURCE-
:STACK-
:STACK-
:STACK-
*
Also in latest version:
~/lisp/cls$ /home/hjstein/
SBCL 1.2.7
* *features*
(:QUICKLISP :SB-BSD-
:ASDF2 :ASDF :OS-UNIX :NON-BASE-
:ANSI-CL :ASH-RIGHT-VOPS :C-STACK-
:COMPARE-
:INLINE-CONSTANTS :LARGEFILE :LINKAGE-TABLE :LINUX :LITTLE-ENDIAN
:MEMORY-
:OS-PROVIDES-
:OS-PROVIDES-POLL :OS-PROVIDES-PUTWC :OS-PROVIDES-
:PACKAGE-
:SB-LDB :SB-PACKAGE-LOCKS :SB-SOURCE-
:SBCL :STACK-
:STACK-
:STACK-
:UNWIND-
It seems to be a combination compiler/gc bug, because I don't run out of memory when I take the declaration out of the definition of v*. So, consider the attached code. Just load it into sbcl to see the crash.
Take a look at the total bytes allocated in the gc log files with gnuplot, and a command like:
plot "< awk '/Total bytes/ {n++ ; print n, $5}' testgc4-ok.log" w l, "< awk '/Total bytes/ {n++ ; print n, $5}' testgc4-crash.log" w l
Without the declaration, it doesn't grow too much over time. With the declaration, it keeps ratcheting up until the heap is exhausted.
I just built SBCL 1.2.10.72-c2a4aec, and it's not as bad. It can survive many calls to testcrash with 1mb arrays, and appears to use less memory in general. However, it's still the case that far more memory is used when the declaration is used, and it crashes pretty quickly when using 2mb arrays.
Also, I find the amount of garbage being retained to be surprising. A 2mb array of doubles is just 16mb, and only 3 are active at any time, which accounts for 48mb, yet the memory usage is becoming as 700mb. Use 5mb arrays instead, for a footprint of 120mb, and it quickly is unable to GC & crashes.