Skip to content

wl_shm (WebKitSharedMemory) buffers accumulate indefinitely on transparent Wayland layer-shell windows #1731

@command-z-z

Description

@command-z-z

wry: 0.55.1 · webkit2gtk: 2.52.3 · GTK: 3.24.52 · Hyprland: 0.55.2 · Kernel: 7.0.8-arch1-1

Description

On Hyprland, a transparent zwlr_layer_shell_v1 window backed by wry + webkit2gtk accumulates /memfd:WebKitSharedMemory (wl_shm) buffers in WebKitWebProcess at a rate proportional to evaluate_script repaint frequency. Old buffers are never freed, causing unbounded RSS growth.

Observed symptoms

  • WebKitWebProcess RSS grows ~100 KB/s at ~1–3 repaints/second
  • After 15 minutes of normal widget use (clock, memo, sysstat):
    $ grep WebKitSharedMemory /proc/<pid>/maps | wc -l
    2034          # expected: 2–3 per window
    # total mapped size: ~153 MB
    
  • Each repaint allocates a new 72–84 KB buffer; no buffer is ever recycled
  • Buffer mmap protection is r--s (read-only shared) — they are held live by the compositor

Root cause hypothesis

wl_buffer.release events are not being delivered back to the client from Hyprland for transparent layer-shell surfaces. Without this event, webkit2gtk cannot mark old wl_shm buffers as reusable and allocates a new one on every frame.

This is likely the underlying mechanism behind the ghost-pixel issue in #1524: Hyprland appears to retain the previous frame's buffer as a compositing base for damage-only repaints on transparent surfaces, and never sends wl_buffer.release for those retained buffers. The bug does not reproduce on Sway (per #1524 reports), consistent with Sway correctly releasing buffers.

Steps to reproduce

  1. Create a zwlr_layer_shell_v1 surface with with_transparent(true) on Hyprland
  2. Call evaluate_script at 1–3 Hz with content that changes the DOM
  3. Monitor buffer count in the WebKitWebProcess maps:
    watch -n 2 "grep WebKitSharedMemory /proc/$(pgrep WebKitWebProcess)/maps | wc -l"
  4. Count grows linearly with no upper bound

Expected behavior

Buffer count stabilises at 2–4 per window (double/triple buffering). wl_buffer.release is received promptly and old buffers are recycled.

Actual behavior

Buffer count grows at ~1–2 per second indefinitely, proportional to repaint frequency. Over hours of runtime this reaches hundreds of MB.

Additional notes

  • Non-transparent windows: not observed — only transparent layer-shell surfaces exhibit this
  • Workaround: use a native GTK widget tree (bypassing WebKit entirely) for transparent windows — zero accumulation
  • WEBKIT_DISABLE_DMABUF_RENDERER=1 has no effect on the accumulation
  • Related: Window Tranparency Not Rendering Correctly #1524 (ghost pixels / incomplete repaints on transparent layer-shell)

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions