From 4150c2e22e93ca6bdf682b0067d430e412db3688 Mon Sep 17 00:00:00 2001 From: Stefan Monnier Date: Tue, 13 Jan 2026 13:41:55 -0500 Subject: [PATCH] (garbage-collect-heapsize): New function The info returned from `garbage-collect` is really handy to track the evolution of the heap size, but sadly it's available only at the cost of running a full GC, which has two big downsides: it's slow, it affects what we're measuring, and it can't be used in `post-gc-hook`. So, this patch makes it available without running the GC. * src/alloc.c (Fgarbage_collect_heapsize): New function, extracted from `Fgarbage_collect`. (Fgarbage_collect): Use it. (syms_of_alloc): defsubr it. * doc/lispref/internals.texi (Garbage Collection): Extract documentation for it from that of `garbage-collect`. --- doc/lispref/internals.texi | 22 ++++++++++++++-------- etc/NEWS | 5 +++++ src/alloc.c | 31 +++++++++++++++++++++++-------- 3 files changed, 42 insertions(+), 16 deletions(-) diff --git a/doc/lispref/internals.texi b/doc/lispref/internals.texi index 70dca8014d0..64e820537e9 100644 --- a/doc/lispref/internals.texi +++ b/doc/lispref/internals.texi @@ -286,13 +286,9 @@ program does not use so much space as to force a second garbage collection). @end quotation -@deffn Command garbage-collect -This command runs a garbage collection, and returns information on -the amount of space in use. (Garbage collection can also occur -spontaneously if you use more than @code{gc-cons-threshold} bytes of -Lisp data since the previous garbage collection.) - -@code{garbage-collect} returns a list with information on amount of space in +@defun garbage-collect-heapsize +This function returns information on the current memory usage. +The return value is a list with information on amount of space in use, where each entry has the form @samp{(@var{name} @var{size} @var{used})} or @samp{(@var{name} @var{size} @var{used} @var{free})}. In the entry, @var{name} is a symbol describing the kind of objects this entry represents, @@ -422,7 +418,17 @@ Total heap size, in @var{unit-size} units. @item free-size Heap space which is not currently used, in @var{unit-size} units. @end table -@end deffn +@end defun + +@deffn Command garbage-collect +This command runs a garbage collection, and returns information on +the amount of space in use. (Garbage collection can also occur +spontaneously if you use more than @code{gc-cons-threshold} bytes of +Lisp data since the previous garbage collection.) + +@code{garbage-collect} returns the same list as shown above for +@code{garbage-collect-heapsize}. +@deffn @defopt garbage-collection-messages If this variable is non-@code{nil}, Emacs displays a message at the diff --git a/etc/NEWS b/etc/NEWS index fc6ba353d9a..32b5ff02cc1 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -3632,6 +3632,11 @@ and other similar functions. * Lisp Changes in Emacs 31.1 ++++ +** New function 'garbage-collect-heapsize'. +Same as 'garbage-collect' but just returns the info from the last GC +without performing a collection. + +++ ** Improve 'replace-region-contents' to accept more forms of sources. It has been promoted from 'subr-x' to the C code. diff --git a/src/alloc.c b/src/alloc.c index c0e23192c0f..a4e97d7a8c3 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -5996,14 +5996,7 @@ DEFUN ("garbage-collect", Fgarbage_collect, Sgarbage_collect, 0, 0, "", doc: /* Reclaim storage for Lisp objects no longer needed. Garbage collection happens automatically if you cons more than `gc-cons-threshold' bytes of Lisp data since previous garbage collection. -`garbage-collect' normally returns a list with info on amount of space in use, -where each entry has the form (NAME SIZE USED FREE), where: -- NAME is a symbol describing the kind of objects this entry represents, -- SIZE is the number of bytes used by each one, -- USED is the number of those objects that were found live in the heap, -- FREE is the number of those objects that are not live but that Emacs - keeps around for future allocations (maybe because it does not know how - to return them to the OS). +It returns the same info as `garbage-collect-heapsize'. Note that calling this function does not guarantee that absolutely all unreachable objects will be garbage-collected. Emacs uses a @@ -6020,8 +6013,29 @@ For further details, see Info node `(elisp)Garbage Collection'. */) specbind (Qsymbols_with_pos_enabled, Qnil); garbage_collect (); unbind_to (count, Qnil); + return Fgarbage_collect_heapsize (); +} + +DEFUN ("garbage-collect-heapsize", Fgarbage_collect_heapsize, + Sgarbage_collect_heapsize, 0, 0, 0, + doc: /* Return a list with info on amount of space in use. +This info may not be fully up to date unless it is called right after +a full garbage collection cycle. +Each entry has the form (NAME SIZE USED FREE), where: +- NAME is a symbol describing the kind of objects this entry represents, +- SIZE is the number of bytes used by each one, +- USED is the number of those objects that were found live in the heap, +- FREE is the number of those objects that are not live but that Emacs + keeps around for future allocations (maybe because it does not know how + to return them to the OS). */) + () +{ struct gcstat gcst = gcstat; + /* FIXME: Maybe we could/should add a field countaing the approximate + amount of memory allocated since the last GC, such as + 'gc_threshold - consing_until_gc'. */ + Lisp_Object total[] = { list4 (Qconses, make_fixnum (sizeof (struct Lisp_Cons)), make_int (gcst.total_conses), @@ -7512,6 +7526,7 @@ N should be nonnegative. */); defsubr (&Smake_finalizer); defsubr (&Sgarbage_collect); defsubr (&Sgarbage_collect_maybe); + defsubr (&Sgarbage_collect_heapsize); defsubr (&Smemory_info); defsubr (&Smemory_use_counts); #if defined GNU_LINUX && defined __GLIBC__ && \