2

Going through the Land of Lisp book, I managed to get to the Grand Theft Wumpus game, that has me define a make-city-edges function. When I try to run it however, SBCL hangs for a while before giving me a very nasty error saying

    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:     0     0     0     0     0     0     0     0     0        0     0 10737418    0   0  0.0000
   1:     0     0     0     0     0     0     0     0     0        0     0 10737418    0   0  0.0000
   2: 27757     0     0     0 19204    70     0    10    54 631392704 505408  2000000    0   0  0.9800
   3:     0     0     0     0     0     0     0     0     0        0     0  2000000    0   0  0.0000
   4:     0     0     0     0     0     0     0     0     0        0     0  2000000    0   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  1638   251     0     0     0 61898752     0  2000000 1523   0  0.0000
   Total bytes allocated    = 1073069936
   Dynamic-space-size bytes = 1073741824
GC control variables:
   *GC-INHIBIT* = true
   *GC-PENDING* = true
   *STOP-FOR-GC-PENDING* = false
fatal error encountered in SBCL pid 85448(tid 140735276667664):
Heap exhausted, game over.

Error opening /dev/tty: Device not configured
Welcome to LDB, a low-level debugger for the Lisp runtime environment.
ldb> 

I've triple-checked to see if I made any mistake, but I couldn't find any.

Here's the function causing the problem:

(defun make-city-edges ()
  (let* ((nodes (loop for i from 1 to *node-num*
                      collect i))
         (edge-list (connect-all-islands nodes (make-edge-list)))
         (cops (remove-if-not (lambda (x)
                                (zerop (random *cop-odds*)))
                              edge-list)))
    (add-cops (edges-to-alist edge-list) cops)))

[here] is the rest of the code if you want to have a look at the other functions, I added it to a GitHub Gist page since it would take up too much space in the question.

What can I do to resolve this? I'm using Emacs 24.4 (9.0) on OSX 10.9 with SLIME and SBCL 1.2.10 for the project.

Electric Coffee
  • 11,733
  • 9
  • 70
  • 131
  • This might be impossible to diagnose without a reproducible test case, the platform, the sbcl version, etc. – Rainer Joswig Apr 12 '15 at 16:43
  • @RainerJoswig what do you suggest I do? – Electric Coffee Apr 12 '15 at 20:29
  • 1
    Well currently this question assumes we own all the book 'land of lisp', it's a great book but without the full code you are limiting the people who could answer this question. Currently only people who own the book and want to redo the exercise can help...Maybe pop the full code here or in a gist linked here. It needs to be complete so anyone here can just compile and test for you. – Baggers Apr 12 '15 at 21:54
  • @Baggers added the remaining code in a link – Electric Coffee Apr 12 '15 at 22:04
  • @ElectricCoffee: that's good. I will look at it, but it will take some time. – Rainer Joswig Apr 13 '15 at 07:00
  • You can try to insert `break`s to find which code path is the problem. – Svante Apr 13 '15 at 08:25
  • @ElectricCoffee Eyeballing it, I don't believe the `find-island` recursion ever terminates. `get-connected` never returns `nil`. – m-n Apr 13 '15 at 17:08
  • @m-n it's identical to the way it was written in my copy of the book, what do you suggest as a fix? Also, why do you think it should return nil? Edit: Nevermind, I found the error. It's in `find-island` – Electric Coffee Apr 13 '15 at 17:15
  • @ElectricCoffee The termination of `find-island`'s recursion was predicated on it returning `nil`:) Was it supposed to be `(when unconnected`, and did you get the whole thing working? – m-n Apr 13 '15 at 17:27
  • @m-n yeah, it works fine now, blazing fast too. Thanks! So, if you could drop the suggestion as an answer, I can approve it :D – Electric Coffee Apr 13 '15 at 17:32

1 Answers1

2

In the linked code,

(defun find-islands (nodes edge-list)
  "returns a list of nodes that aren't interconnected"
  (let ((islands nil))
    (labels ((find-island (nodes)
           (let* ((connected (get-connected (car nodes) edge-list))
              (unconnected (set-difference nodes connected)))
         (push connected islands)
         (when connected
           (find-island unconnected)))))
      (find-island nodes))
    islands))

(when connected should be (when unconnected.

A few tips for debugging heap exhaustion:

  1. Check that your loops and recursions actually terminate. (That's what led us to this solution -- get-connected never returns nil, so find-island would recurse forever.)
  2. CL's trace can be useful, as well as the traditional adding of print statements.
  3. C-c C-c in SLIME after the program has run for a bit but before heap exhaustion might provide a useful backtrace.

E.g. of the backtrace:

  0: ((:INTERNAL TRAVERSE GET-CONNECTED) NIL)
      Locals:
        NODE = NIL
        #:G11908 = ((2 . 21) (20 . 22) (22 . 20) (9 . 28) (28 . 9) (2 . 7) ...)
        EDGE-LIST = ((8 . 3) (3 . 8) (18 . 7) (7 . 18) (26 . 23) (23 . 26) ...)
        VISITED = (NIL)
  1: (GET-CONNECTED NIL ((8 . 3) (3 . 8) (18 . 7) (7 . 18) (26 . 23) (23 . 26) ...))
      Locals:
        NODE = NIL
        EDGE-LIST = ((8 . 3) (3 . 8) (18 . 7) (7 . 18) (26 . 23) (23 . 26) ...)
        VISITED = (NIL)
  2: ((:INTERNAL FIND-ISLAND FIND-ISLANDS) NIL)
      Locals:
        NODES = NIL
        ISLANDS = ((NIL) (NIL) (NIL) (NIL) (NIL) (NIL) ...)
        EDGE-LIST = ((8 . 3) (3 . 8) (18 . 7) (7 . 18) (26 . 23) (23 . 26) ...)
  3: (FIND-ISLANDS (1 2 3 4 5 6 ...) ((8 . 3) (3 . 8) (18 . 7) (7 . 18) (26 . 23) (23 . 26) ...))
      Locals:
        NODES = (1 2 3 4 5 6 ...)
        EDGE-LIST = ((8 . 3) (3 . 8) (18 . 7) (7 . 18) (26 . 23) (23 . 26) ...)
        ISLANDS = ((NIL) (NIL) (NIL) (NIL) (NIL) (NIL) ...)

That might lead us to say "I didn't think a node would ever be nil, and islands being ((nil) (nil) (nil) ...) seems broken."

m-n
  • 1,476
  • 1
  • 9
  • 9