Subject: bug#79023: 30.1.90; Suspicion of memory leak on internal_redisplay (MacOS)

From: Eli Zaretskii <[email-masked]>
Date: Wed, 16 Jul 2025 15:02:40 +0300

> From: Przemysław Alexander Kamiński
>  <[email-masked]>
> Cc: [email-masked]
> Date: Wed, 16 Jul 2025 08:49:47 +0200
> 
> Yesterday I was able to hookup MacOS' Instruments.app to build Emacs. Took some effort to figure out, but once done it was rather easy. I'll make a short note and publish the steps.
> 
> Findings:
> - There are multiple leaks, but most of them are very small in total they accrue ~1m per minute
> - The total run was ~2.5m (it slows Emacs down so it's hard to use it all the time) and I cut off initialization leaks (~1.5m, some related to Toolbar initialization)
> - I'm attaching two text files (not sure if it won't bounce)
>   - First one are few example of complex loops - they seem to hit lisp_allign_malloc which seems to be related to MacOS-specific code
>   - Second one are root loops.
> 
> I found few other weird things, e.g. it seems that opening a single midsize buffer processed approx. 2GiB of memory and that a single symbol allocates 1KiB of memory, but I don't think it's the proper thread to discuss further.
> 
> Of course there's more but sharing in text form is very difficult. In case someone wants to reproduce by themselves, what it takes is to add task/debug entitlements (see attached debug.plist) through signing. I had to remove com.apple.FinderInfo from emacs-plus build, not sure where it came from. Build was with debug symbols for easier debugging. Commands I used:
> 
> $ xattr -d com.apple.FinderInfo /path/to/Emacs.app
> $ codesign -s - -v -f --entitlements /path/to/debug.plist /path/to/Emacs.app
> 
> After that I started Instruments.app set app bundle for analysis and launched from there.
> 
> Lot of interesting info, but slows down considerably when constantly probed. I'm somewhat stoked about this because I'm optimization freak and Emacs speed on MacOS wasn't something great - it usually deteriorates after hours - I blamed fancy packages like Marginalia, but if it leaks drops on small allocations it would make sense why it accelerated the process.

Thanks, but I don't yet understand how to use the information you
posted for trying to find the alleged memory leaks.  Some questions
below.

I also am not sure these are real leaks.  Emacs Lisp programs trigger
memory allocation when they create Lisp objects, but they don't
themselves free memory they allocated this way when the objects are no
longer needed.  Instead, the process known as "garbage collection"
(GC) is initiated by Emacs from time to time, and "collects garbage"
by finding Lisp objects no longer referenced by any other object, and
freeing their memory.  (Apologies for the lecture if you already know
all that.)  Thus, programs that expect memory to be released
immediately when the object goes out of scope will think Emacs is a
very leaky application, because that's not how Emacs Lisp works.

Are you sure the information you collected is not of this kind?

> Root leaks
> 
> _malloc_zone_malloc_instrumented_or_legacy
> lmalloc
> make_blv
> Fmake_local_variable
> F636f6d70696c6174696f6e2d6d6f6465_compilation_mode_0
> Ffuncall
> F656d6163732d6c6973702d636f6d70696c6174696f6e2d6d6f6465_emacs_lisp_compilation_mode_0
> Ffuncall
> F636f6d702d2d72756e2d6173796e632d776f726b657273_comp__run_async_workers_0
> Ffuncall
> F6e61746976652d2d636f6d70696c652d6173796e63_native__compile_async_0
> Ffuncall
> F6e61746976652d636f6d70696c652d6173796e63_native_compile_async_0
> eval_sub
> Fprogn
> funcall_lambda
> Ffuncall
> Ffuncall
> F74696d65722d6576656e742d68616e646c6572_timer_event_handler_0
> Ffuncall
> timer_check_2
> main
> start

What are "root leaks", and how to interpret the above sequence of
function names?

> 1	 Malloc 544,00 KiB - 1 nodes	Complex Cycle
> _malloc_zone_memalign
> lisp_align_malloc
> Fcons
> Fcopy_sequence
> timer_check
> readable_events
> get_input_pending
> main
> start

What does the above attempt to tell?

Thanks.