Skip to content

Memory leak: Application views + screenshots never release memory to the system - #2437

Open
lewisgoddard wants to merge 2 commits into
mainfrom
fix/lewisgoddard/screenshot-branding-leak
Open

Memory leak: Application views + screenshots never release memory to the system#2437
lewisgoddard wants to merge 2 commits into
mainfrom
fix/lewisgoddard/screenshot-branding-leak

Conversation

@lewisgoddard

@lewisgoddard lewisgoddard commented Jul 27, 2026

Copy link
Copy Markdown
Member

Every AppInfoView (and all of its screenshots) stayed alive after being popped from the navigation view, so browsing leaked hundreds of MB that were never reclaimed. (I initially thought this was just a screenshot issue.)

Now AppInfoView is free'd within the app memory pool when navigating away, and closing the window releases all free'd memory to the system.

Before: Browing apps brought memory usage to 1.4GiB, not free'd on close.
After: Browsing apps brought memory usage to ~800MiB, free'd to ~500MiB on close.

…gleton

set_branding() connected a lambda to the process-lifetime
Granite.Settings singleton that captured its local `package`
parameter. Capturing a local makes Vala emit g_signal_connect_data()
with a heap closure block holding strong refs to both the Screenshot
widget and the Package, instead of the g_signal_connect_object() it
emits when only `this` is captured. Nothing ever disconnected, so
every Screenshot ever displayed stayed alive for the life of the
process along with its decoded image data.

Connect in construct(), where no local is in scope to capture, and
keep the colour in a field. This also fixes set_branding() stacking
an additional permanent handler on each call.
…close

The motion-controller enter/leave handlers and the scroll value-changed
handler captured construct-locals, so Vala emitted g_signal_connect_data()
with a strong reference back to the view. Because the view owns those child
widgets, that closed a reference cycle: every AppInfoView (and all of its
screenshots) stayed alive after being popped from the navigation view, so
browsing leaked hundreds of MB that were never reclaimed.

Promote the captured locals to fields so the handlers capture only `this`
and Vala emits the weak g_signal_connect_object(), letting the view
finalize on navigation. Also malloc_trim() once the window is destroyed so
closing it returns the freed browsing memory to the OS.
@ryonakano

Copy link
Copy Markdown
Member

How did you find this solution? malloc_trim() is a way to forcibly frees memory which I personally feel like a workaround.

@lewisgoddard

Copy link
Copy Markdown
Member Author

Only destroying the app views on close seemed to leave the memory allocated to the app, so I used malloc_trim(). I'm not super farmiliar with Vala, so I used what I know from C, hence the import. Would love to know what Vala method I probably should be using.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants