Description
On Linux, a Ryn 0.32.0 application using WebKitGTK continues to grow memory while its window is open and completely idle. In one clean idle interval, the main host process gained about 5 MiB of anonymous/private memory in 60 seconds. The WebKit web and network subprocesses remained effectively flat during the same interval.
The test application has also been observed rising from about 160 MB at startup to about 228 MB after one minute without user interaction. Repeated launch/open/close experiments showed continued native-memory growth rather than a stable plateau.
The equivalent Windows build of the same application, which uses WebView2, settles at about 26 MB after startup. That makes shared application state or ordinary managed .NET retention unlikely and points toward the Linux host-side Ryn/Saucer/GTK event or rendering path.
The strongest new observation is that the growth is visibility-dependent: while the window is visible and untouched, the host process uses roughly 5-12% CPU while anonymous memory rises. Moving the tiled window fully outside the visible monitor area under niri drops host CPU use to about 0%, after which memory stabilizes or is reclaimed instead of continuing to grow. Bringing the window back into view resumes both the CPU use and the memory slope. That coupling points to active rendering/compositing or frame scheduling in the Linux webview path rather than a passive background leak or an available-memory effect.
Environment
|
|
| Ryn packages |
0.32.0 (Ryn and plugins) |
| Application runtime |
.NET 10, x86-64 |
| OS |
CachyOS Linux, kernel 7.2.0-1-cachyos |
| Session / compositor |
Wayland / niri |
| WebKitGTK |
webkitgtk-6.0 2.52.6-1 |
| GTK |
gtk4 4.22.4 |
| GPU / driver |
NVIDIA GeForce RTX 4070 / nvidia-utils 610.57.04 |
| Host memory |
30 GiB RAM, about 8.9 GiB available during measurement; 62 GiB swap |
| Windows comparison |
Same application and frontend using Ryn/WebView2 settles at about 26 MB after roughly 10 seconds |
Visibility dependence
| State |
Host CPU |
Memory trend |
| Visible, idle |
roughly 5-12% |
steady anonymous growth (e.g. +5,004 KiB over 60 s above) |
| Fully off the visible monitor (occluded) |
about 0% |
stabilizes; memory reclaimed rather than growing |
The visible-state growth repeats across measurement sessions, and the occluded state stops both CPU use and growth — the process does not keep allocating in the background while nothing is being painted.
Diagnostics performed
Managed-memory evidence
Repeated launch/open/close measurements compared process memory with the .NET managed heap:
- Managed GC heap stayed around 1.6-1.7 MiB while host anonymous memory grew by tens of MiB across cycles.
- Thread count remained stable at about 55.
- A source audit found no retained launched-application object, accumulating event subscription, or unbounded application collection explaining the growth.
Temporary System.Diagnostics.Process wrappers found during that audit were explicitly disposed. That fixed real native handle ownership defects but did not stop the observed growth.
Optional application integration disabled
As a diagnostic, the optional application integration (external application discovery/import) was completely disabled on Linux: the module was not loaded and its IPC surface was removed before any event handlers could attach. The major Linux/Windows memory difference remained, so that integration is not the source.
Frontend lifecycle audit
The frontend cleanup paths were audited for Ryn IPC subscriptions, DOM listeners, Vue watchers, intervals/timeouts, and session callbacks. Explicit cleanup exists for the long-lived listeners and timers, and repeated initialization/detachment cycles did not reveal a recurring idle allocator or an unbounded collection.
Process split
The WebKit web and network subprocesses were stable over the measured idle minute; growth was concentrated in the main .NET/Ryn host process. This does not look like a growing JavaScript heap in WebKitWebProcess.
Visibility dependence (strongest evidence)
While the window is visible and untouched, the host process uses roughly 5-12% CPU while anonymous memory rises. Moving the tiled window fully outside the visible monitor area under niri (fully occluded) drops CPU use to about 0%, after which memory stabilizes or is reclaimed rather than continuing to grow; returning the window to view resumes both.
This distinguishes an active paint/frame/compositor path from a passive leak or an available-memory effect:
- Available system memory does not change when the window is moved off the visible monitor, so growth is tracking render activity, not allocator or page-cache policy reacting to memory pressure.
- A passive allocation leak (managed or native) would keep allocating whether or not the window is visible; here the growth stops when nothing is being composited.
- Near-zero CPU while occluded, plus stabilized or reclaimed memory, is the signature of a workload tied to visible composition: when there is nothing to paint, the frame/compositor loop idles and the resources it would have used are released.
The correlation strongly implicates active rendering/compositing or frame scheduling in the Linux webview path, but it does not prove which component performs the recurring work; a native allocation stack profile is still required for final attribution.
Available system memory
The Linux host had about 8.9 GiB available during measurement and substantial swap capacity. More available memory can change allocator trimming and cache retention, so absolute working-set values can differ across machines. It does not normally explain a repeatable, approximately linear increase in private anonymous pages while the application is idle.
Taken together, the strongest evidence is the visibility-coupled host behavior: host CPU and anonymous memory rise together while the window is visible, and both stop when it is fully off the visible monitor, while the managed GC heap and WebKit child processes remain stable throughout. That indicates recurring native work tied to visible rendering/compositing in the Linux webview path — allocations or retained allocator arenas inside native libraries loaded by the Ryn host — rather than Linux merely assigning extra file cache to the process or a steady background leak.
Suspected area
The evidence — especially the visibility dependence — points to the Linux host-side Ryn/Saucer/GTK/WebKit integration, with active rendering/compositing or frame scheduling as the recurring workload. The visible-versus-occluded behavior weights the frame/render path: an occluded window stops consuming CPU and stops growing, so the work is tied to visible composition rather than a steady background allocator. Potentially:
- continuous frame scheduling or redraw invalidation while the window is visible;
- GTK/WebKit host callbacks whose native payloads are not released;
- frame/render invalidation or texture/surface allocations retained in the host process;
- NVIDIA/EGL/GL resource accumulation associated with the embedded window;
- allocator caching caused by a recurring native workload that should not exist while idle.
This does not prove which native component owns the allocation or the frame traffic; a native allocation stack profile is required for final attribution.
Operating system
Linux
OS version
CachyOS 7.0.2-1
Ryn version
0.30.0, 0.32.0
.NET version
10.0.111
Steps to reproduce
- Build and run the test application on Linux with Ryn 0.32.0.
- Leave the application window visible and do not interact with it.
- Sample
/proc/<pid>/smaps_rollup every 10 seconds for at least one minute.
- Separately sample the
WebKitWebProcess and WebKitNetworkProcess children.
- Observe growth in the main application process while the WebKit children remain stable.
- While the window is still visible and idle, also sample host CPU use alongside the memory slope.
- Move the tiled window fully outside the visible monitor area (under niri, so it is not composited onto any visible output) and leave it untouched.
- Sample the same metrics for at least one minute in the occluded state: CPU should drop to about 0% and the memory slope should flatten, with stabilization or reclamation instead of growth.
- Move the window back into the visible area and confirm CPU use and memory growth resume.
The test application is a frameless Ryn window containing a Vue/Vite frontend. No external application needs to be launched to reproduce the idle growth.
Expected behavior
After normal WebKit/GTK startup and cache warm-up, an untouched Ryn window should reach a stable memory range. Private anonymous memory should not keep increasing by several MiB per minute indefinitely.
Actual behavior
Values below are from /proc/<pid>/smaps_rollup and are in KiB.
| Process |
Metric |
Start |
60 seconds |
Delta |
| test application host |
Anonymous |
163,532 |
168,536 |
+5,004 |
| test application host |
Private Dirty |
187,420 |
192,436 |
+5,016 |
| test application host |
PSS |
277,736 |
282,650 |
+4,914 |
| WebKit web process 1 |
Anonymous |
109,856 |
109,968 |
+112 |
| WebKit web process 2 |
Anonymous |
90,060 |
89,652 |
-408 |
| WebKit network process |
Anonymous |
24,796 |
24,796 |
0 |
During a later observation, the host process reported:
VmHWM: 435,136 KiB
VmRSS: 435,136 KiB
RssAnon: 168,840 KiB
RssFile: 251,892 KiB
RssShmem: 14,404 KiB
- Threads: 55
Absolute RSS includes shared libraries and mapped files, so anonymous/private growth is the important signal.
Logs and output
Additional context
A small public minimal reproducer has not yet been prepared — the measurements above come from the full test application. Assistance reproducing with a minimal Ryn 0.32.0 Linux application containing one idle frameless webview would be welcome, in particular to inspect:
- whether the main loop continuously queues callbacks or invalidations;
- allocation/free balance around Saucer Linux event callbacks;
- GTK signal payload and closure ownership;
- WebKitGTK user-content-manager/message callback ownership;
- EGL/GL surface and texture lifecycle;
- whether hardware acceleration changes the anonymous-memory slope.
Useful comparison runs:
- Empty static HTML versus the Vue frontend.
- Normal decorated window versus frameless window.
- Hardware acceleration enabled versus disabled.
- NVIDIA versus Mesa/software rendering.
- Ryn host without optional plugins versus the current plugin set.
heaptrack or equivalent native allocation profiling for a two-minute untouched idle window.
Most likely layer: Ryn/Saucer/GTK/WebKitGTK Linux host integration.
Confidence: moderate-to-high. Managed application retention, optional-integration discovery, and WebKit child-process heap growth have been directly reduced or contradicted by measurement. Exact native allocation ownership remains unproven until a native allocation profiler captures the growing stacks.
Description
On Linux, a Ryn 0.32.0 application using WebKitGTK continues to grow memory while its window is open and completely idle. In one clean idle interval, the main host process gained about 5 MiB of anonymous/private memory in 60 seconds. The WebKit web and network subprocesses remained effectively flat during the same interval.
The test application has also been observed rising from about 160 MB at startup to about 228 MB after one minute without user interaction. Repeated launch/open/close experiments showed continued native-memory growth rather than a stable plateau.
The equivalent Windows build of the same application, which uses WebView2, settles at about 26 MB after startup. That makes shared application state or ordinary managed .NET retention unlikely and points toward the Linux host-side Ryn/Saucer/GTK event or rendering path.
The strongest new observation is that the growth is visibility-dependent: while the window is visible and untouched, the host process uses roughly 5-12% CPU while anonymous memory rises. Moving the tiled window fully outside the visible monitor area under niri drops host CPU use to about 0%, after which memory stabilizes or is reclaimed instead of continuing to grow. Bringing the window back into view resumes both the CPU use and the memory slope. That coupling points to active rendering/compositing or frame scheduling in the Linux webview path rather than a passive background leak or an available-memory effect.
Environment
Rynand plugins)7.2.0-1-cachyoswebkitgtk-6.0 2.52.6-1gtk4 4.22.4nvidia-utils 610.57.04Visibility dependence
The visible-state growth repeats across measurement sessions, and the occluded state stops both CPU use and growth — the process does not keep allocating in the background while nothing is being painted.
Diagnostics performed
Managed-memory evidence
Repeated launch/open/close measurements compared process memory with the .NET managed heap:
Temporary
System.Diagnostics.Processwrappers found during that audit were explicitly disposed. That fixed real native handle ownership defects but did not stop the observed growth.Optional application integration disabled
As a diagnostic, the optional application integration (external application discovery/import) was completely disabled on Linux: the module was not loaded and its IPC surface was removed before any event handlers could attach. The major Linux/Windows memory difference remained, so that integration is not the source.
Frontend lifecycle audit
The frontend cleanup paths were audited for Ryn IPC subscriptions, DOM listeners, Vue watchers, intervals/timeouts, and session callbacks. Explicit cleanup exists for the long-lived listeners and timers, and repeated initialization/detachment cycles did not reveal a recurring idle allocator or an unbounded collection.
Process split
The WebKit web and network subprocesses were stable over the measured idle minute; growth was concentrated in the main .NET/Ryn host process. This does not look like a growing JavaScript heap in
WebKitWebProcess.Visibility dependence (strongest evidence)
While the window is visible and untouched, the host process uses roughly 5-12% CPU while anonymous memory rises. Moving the tiled window fully outside the visible monitor area under niri (fully occluded) drops CPU use to about 0%, after which memory stabilizes or is reclaimed rather than continuing to grow; returning the window to view resumes both.
This distinguishes an active paint/frame/compositor path from a passive leak or an available-memory effect:
The correlation strongly implicates active rendering/compositing or frame scheduling in the Linux webview path, but it does not prove which component performs the recurring work; a native allocation stack profile is still required for final attribution.
Available system memory
The Linux host had about 8.9 GiB available during measurement and substantial swap capacity. More available memory can change allocator trimming and cache retention, so absolute working-set values can differ across machines. It does not normally explain a repeatable, approximately linear increase in private anonymous pages while the application is idle.
Taken together, the strongest evidence is the visibility-coupled host behavior: host CPU and anonymous memory rise together while the window is visible, and both stop when it is fully off the visible monitor, while the managed GC heap and WebKit child processes remain stable throughout. That indicates recurring native work tied to visible rendering/compositing in the Linux webview path — allocations or retained allocator arenas inside native libraries loaded by the Ryn host — rather than Linux merely assigning extra file cache to the process or a steady background leak.
Suspected area
The evidence — especially the visibility dependence — points to the Linux host-side Ryn/Saucer/GTK/WebKit integration, with active rendering/compositing or frame scheduling as the recurring workload. The visible-versus-occluded behavior weights the frame/render path: an occluded window stops consuming CPU and stops growing, so the work is tied to visible composition rather than a steady background allocator. Potentially:
This does not prove which native component owns the allocation or the frame traffic; a native allocation stack profile is required for final attribution.
Operating system
Linux
OS version
CachyOS 7.0.2-1
Ryn version
0.30.0, 0.32.0
.NET version
10.0.111
Steps to reproduce
/proc/<pid>/smaps_rollupevery 10 seconds for at least one minute.WebKitWebProcessandWebKitNetworkProcesschildren.The test application is a frameless Ryn window containing a Vue/Vite frontend. No external application needs to be launched to reproduce the idle growth.
Expected behavior
After normal WebKit/GTK startup and cache warm-up, an untouched Ryn window should reach a stable memory range. Private anonymous memory should not keep increasing by several MiB per minute indefinitely.
Actual behavior
Values below are from
/proc/<pid>/smaps_rollupand are in KiB.During a later observation, the host process reported:
VmHWM: 435,136 KiBVmRSS: 435,136 KiBRssAnon: 168,840 KiBRssFile: 251,892 KiBRssShmem: 14,404 KiBAbsolute RSS includes shared libraries and mapped files, so anonymous/private growth is the important signal.
Logs and output
Additional context
A small public minimal reproducer has not yet been prepared — the measurements above come from the full test application. Assistance reproducing with a minimal Ryn 0.32.0 Linux application containing one idle frameless webview would be welcome, in particular to inspect:
Useful comparison runs:
heaptrackor equivalent native allocation profiling for a two-minute untouched idle window.Most likely layer: Ryn/Saucer/GTK/WebKitGTK Linux host integration.
Confidence: moderate-to-high. Managed application retention, optional-integration discovery, and WebKit child-process heap growth have been directly reduced or contradicted by measurement. Exact native allocation ownership remains unproven until a native allocation profiler captures the growing stacks.