Releases: luohoufu/ghostty
Releases 路 luohoufu/ghostty
Release list
1.2.4
Fix memory leak when pruning scrollback with non-standard pages (#10251) This _finally_ resolves #9962 (and the myriad of dupes). The core issue was that when a non-standard size page is reused as part of our scrollback pruning, it was resized to be standard size, which caused our future frees to believe it was pooled and not call `munmap` properly. The solution I chose was to never reuse non-standard sized pages. If during scrollback pruning we detect a non-standard page, we destroy it and re-alloc. This frees the old memory and reuses pool memory for the new page. As part of this, I also introduced a custom page allocator that uses macOS's mach kernel virtual memory tagging feature to specifically tag our PageList memory. I was able to use this in conjunction with Instruments and `footprint` to verify that our PageList memory was previously not freed and is now successfully freed. **No AI was used in my work here.** AI was used by others in their analysis of this issue that I used the results of to help guide me and give me other things to consider, but the ultimate understanding and fix was all done via my own meat sticks. ## Detailed Explainer Ghostty uses a memory pool of fixed-size `mmap`-ed pages to serve as the backing memory for our terminal. If the terminal requires a non-standard (larger) amount of memory due to an abundance of emoji, styles, hyperlinks, etc. then we allocate non-pooled pages directly with `mmap`. When freeing our pages, if it is `<= standard size` we just put it back into the memory pool. If it is larger, we `munmap` it. This explains and defines both a _standard_ and therefore _non-standard_ page. Ghostty also has the concept of a "scrollback limit" (exposed to the user via the `scrollback-limit` config). This caps the size of our scrollback or history. When we reach this limit, we have a trick that we do: to avoid allocation, we reuse the oldest page in the history. Unfortunately, as part of this process, we were resizing the underlying memory to be standard size again. This was causing our future frees to believe this was pooled memory, and never unmap it. This was the main source of the leak. ## Thanks Big shout out to @grishy for being the person that finally got me a reproduction so I could analyze the issue for myself. His own analysis got to the same conclusion as me but thanks to the reproduction I was able to verify both our understandings independently.