Hi Juho,
Would your patch address, the following issue mentioned in
http://article.gmane.org/gmane.lisp.steel-bank.devel/10194/?
* how to explain why Lisp lets itself get into a place where it
cannot recover memory. All of the memory allocated during the call to
parse-text is garbage; it can all be freed. But both SBCL and Allegro
are unable to freed the memory without running out of memory during
the process.
Cheers,
David
On Mon, Jun 02, 2008 at 07:00:13AM +0300, Juho Snellman wrote:
> Juho Snellman <jsnell@...> writes:
> > No, the best thing would be to have a GC that doesn't die horribly
> > when there is too much data in old generations.
>
> Given that it doesn't look like anybody is currently fixing the
> problem for real, but reports of this problem are becoming more and
> more frequent, I wonder if we should just put in some kludge for
> now. For example like the attached one, which forces a full GC if
> before a GC it looks like the heap is getting too full (the exact
> definition of too full depends on the size of the heap, and the
> breakdown between allocated data needs to be copied vs. data that
> doesn't).
>
> diff --git a/src/code/gc.lisp b/src/code/gc.lisp
> index e6abbb1..3e119e6 100644
> --- a/src/code/gc.lisp
> +++ b/src/code/gc.lisp
> @@ -196,6 +196,51 @@ run in any thread.")
> (declaim (type cons *gc-epoch*))
> (defvar *gc-epoch* (cons nil nil))
>
> +(defconstant +max-gen+ 6)
> +(defvar *min-free-heap-factor* 16)
> +
> +;;; Possibly trigger a full GC even if only a minor GC was requested,
> +;;; if it looks like the heap is too full. This is just a kludge to
> +;;; work around the way gencgc is unable to deal gracefully with
> +;;; running out of heap during GC, and worse yet tends to cause heap
> +;;; exhaustion due to not GCing old generations frequently enough on
> +;;; some workloads.
> +;;;
> +;;; This is a horribly kludge. It's not foolproof, and it raises data
> +;;; into the oldest generation way too eagerly (since that's the
> +;;; result of a full GC). But the bug reports about this known issue
> +;;; are becoming more and more frequent, so it seems that even a
> +;;; kludge is better than nothing. -- JES, 2008-06-01
> +(defun force-full-gc-p ()
> + #!-gencgc
> + nil
> + #!+gencgc
> + (let ((movable-count 0)
> + (immovable-count 0))
> + ;; Count the number of pages in use currently.
> + (dotimes (i sb!vm::last-free-page)
> + (symbol-macrolet ((page (deref sb!vm::page-table i)))
> + (let* ((gen (slot page 'sb!vm::gen))
> + (flags (slot page 'sb!vm::flags))
> + (free-p (zerop (ldb (byte 3 2) flags)))
> + (large-p (logbitp 6 flags)))
> + (unless free-p
> + (if (or large-p
> + (eql gen 6))
> + (incf immovable-count)
> + (incf movable-count))))))
> + (< sb!vm::page-table-pages
> + (+ immovable-count
> + movable-count
> + ;; Account for the GC being copying. Any moveable data might
> + ;; use up double the storage during GC. If there aren't that
> + ;; many moveable pages around, but the heap is instead
> + ;; filling up with large objects, still try to ensure that
> + ;; we keep 1/16th (arbitrary) of the heap free for further
> + ;; allocations.
> + (max movable-count
> + (truncate sb!vm::page-table-pages *min-free-heap-factor*))))))
> +
> (defun sub-gc (&key (gen 0))
> (unless (eq sb!thread:*current-thread*
> (sb!thread:mutex-value *already-in-gc*))
> @@ -214,9 +259,10 @@ run in any thread.")
> (let ((old-usage (dynamic-usage))
> (new-usage 0))
> (unsafe-clear-roots)
> -
> (gc-stop-the-world)
> (let ((start-time (get-internal-run-time)))
> + (when (force-full-gc-p)
> + (setf gen +max-gen+))
> (collect-garbage gen)
> (setf *gc-epoch* (cons nil nil))
> (incf *gc-run-time*
> @@ -224,7 +270,6 @@ run in any thread.")
> (setf *gc-pending* nil
> new-usage (dynamic-usage))
> (gc-start-the-world)
> -
> ;; In a multithreaded environment the other threads will
> ;; see *n-b-f-o-p* change a little late, but that's OK.
> (let ((freed (- old-usage new-usage)))
> @@ -258,7 +303,7 @@ run in any thread.")
> #!+(and sb-doc (not gencgc))
> "Initiate a garbage collection. GEN may be provided for compatibility with
> generational garbage collectors, but is ignored in this implementation."
> - (sub-gc :gen (if full 6 gen)))
> + (sub-gc :gen (if full +max-gen+ gen)))
>
> (defun unsafe-clear-roots ()
> ;; KLUDGE: Do things in an attempt to get rid of extra roots. Unsafe
> diff --git a/src/code/print.lisp b/src/code/print.lisp
> index e235f4b..69c0e78 100644
> diff --git a/src/code/room.lisp b/src/code/room.lisp
> index 87770c1..029564d 100644
> --- a/src/code/room.lisp
> +++ b/src/code/room.lisp
> @@ -222,6 +222,8 @@
> (gen (signed 8))))
> (declaim (inline find-page-index))
> (define-alien-routine "find_page_index" long (index long))
> + (define-alien-variable "page_table_pages" long)
> + (define-alien-variable "last_free_page" long)
> (define-alien-variable "page_table" (* (struct page))))
>
> ;;; Iterate over all the objects allocated in SPACE, calling FUN with
>
> --
> Juho Snellman
> -------------------------------------------------------------------------
> This SF.net email is sponsored by: Microsoft
> Defy all challenges. Microsoft(R) Visual Studio 2008.
> http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
> _______________________________________________
> Sbcl-devel mailing list
> Sbcl-devel@...
> https://lists.sourceforge.net/lists/listinfo/sbcl-devel
|