[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Lisp-level macro to avoid excessive GC in memory-allocating code (wa
From: |
Ihor Radchenko |
Subject: |
Re: Lisp-level macro to avoid excessive GC in memory-allocating code (was: Larger GC thresholds for non-interactive Emacs) |
Date: |
Fri, 01 Jul 2022 19:12:05 +0800 |
Eli Zaretskii <eliz@gnu.org> writes:
>> > Please don't forget that GC doesn't only collects unused Lisp objects,
>> > it also does other useful memory-management related tasks. It
>> > compacts buffer text and strings, and it frees unused slots in various
>> > caches (font cache, image cache, etc.). You can find in the archives
>> > discussions where innocently-looking code could cause Emacs run out of
>> > memory because it used too many fonts without flushing the font cache
>> > (any program that works on the list of fonts returned by the likes of
>> > x-list-fonts is in danger of bumping into that).
>>
>> Then, if we decide to implement the macro I am suggesting, such macro
>> should not affect memory allocation of such sensitive objects: font
>> cache, image cache, etc.
>
> Why not? The same could happen with those cached objects. And doing
> these jobs does take CPU time.
I do not have enough knowledge on the topic to argue on this. What I
wanted to say is that we can make some objects to be not affected by the
suggested macro if there are reasons to believe that it could be too
dangerous.
>> 1. In addition to directly bumping the TOTAL counter of newly allocated
>> memory, we can introduce a new LOCAL counter holding recent
>> allocations within current sexp.
>> 2. Every time we return from a sexp/self-quoting object into assignment,
>> if we are inside the proposed macro and also assigning value to one
>> of the pre-defined symbols, increase the upper LOCAL counter in the
>> parent sexp. Otherwise, do not change the upper LOCAL counter.
>> 3. Perform GC according to TOTAL-LOCAL threshold value.
>> 4. When exiting the macro, set LOCAL to 0, unless inside another such
>> macro.
>
> Is this aligned with what the implementation of the Lisp interpreter
> actually does? I'm not sure we know, where we allocate memory for
> Lisp data, whether we are going to bind some variable to the produced
> data. Thus "count recent allocations within the current sexp" sounds
> like non-trivial to implement.
I am not 100% sure, but AFAIK lisp interpreter always knows the current
lisp nesting level. The extra C-level variable I suggest may be an array
of max-lisp-eval-depth size. Then, at every given sexp nesting level, if
we know the current level, we automatically gain access to the
appropriate extra in-sexp memory allocation info.
It is also trivial to ensure that all the deeper nesting levels in the
array are set to 0 (after appropriate update of the value corresponding
to the current nesting)
> And what do you mean by "pre-defined symbols"? what makes a symbol
> "pre-defined"?
I was referring to
(with-no-gc '(pre-defined-symbol1 symbol2 ...) ...)
I am not sure if my description above is 100% accurate, but the general
idea is:
1. Introduce LOCAL variable holding total memory used to allocate
objects within current lisp nesting. This variable can be represented
by an array of max-lisp-eval-depth size.
2. GC is triggered based on TOTAL-LOCAL instead of currently used TOTAL.
3. LOCAL[i]+=LOCAL[i+1]; LOCAL[i+1]=0 should be done after anything
potentially involving recursive sexp call, except symbol slot
assignments to non-"pre-defined" symbols.
4. If we are assigning symbol value slot and the symbol value is not
"pre-defined" in the macro, LOCAL is not incremented in 3, which will
make all the memory allocated inside that sexp to be counted towards
next GC threshold.
The above effectively allows GCs only upon returning from symbol
assignments (in let/setq/setf/etc). But I believe that it should not be
a big deal.
> I also am not sure we have the "parent sexp" in hand, but I'll let
> experts on the Lisp interpreter to comment on that.
Agree. I am nowhere expert. Mostly tried to look into setq
implementation I come up with something.
Hopefully people more familiar with the interpreter chime in.
Best,
Ihor