Skip to content

System-wide OOM after prolonged lock-screen playback on NVIDIA (kernel memory, not extension memory) #24

Description

@0fif

Up front

I do not think this is your bug, and I want to be clear about that before
describing it. The extension's own memory behaviour is fine and its cleanup is
correct — I checked. But it appears to be the trigger for a kernel-level leak in
the NVIDIA driver, and you may want to know, and may be able to mitigate.

Environment

  • Live Lock Screen 3.2.0 (version 8)
  • GNOME Shell 50.3, Wayland
  • Fedora 44, kernel 7.1.4-200.fc44.x86_64
  • NVIDIA RTX 3090, driver 610.43.03 (open kernel module)
  • GStreamer 1.28.5, gstreamer1-plugin-gtk4-0.15.2
  • 32 GB RAM
  • Also enabled: unblank@sun.wxg@gmail.com (prevents screen blanking — likely
    relevant, see below)

What happened

Two system-wide OOM events, 19 processes killed by the kernel, including the
audio server, input method, file manager, and terminal.

The memory was not held by the extension or its player process. At the
moment of the second OOM, the player process (gjs, PID 15373) held 374 kB of
anonymous memory. Every process on the system combined held 213 MB, on a 32 GB
machine. ~30 GB was held by kernel-side allocations, and the OOM killer was
invoked from the NVIDIA driver's own KMS thread:

KMS thread invoked oom-killer: gfp_mask=0x40dc0(GFP_KERNEL|__GFP_ZERO|__GFP_COMP), order=3
slab_unreclaimable:4409875        (16.8 GB)
sec_pagetables:2841472kB          (2.8 GB, with no VM running)
all_unreclaimable? yes

Your code is not at fault

I read through core/player_process.js and extension.js before filing, so
you do not have to defend against the obvious guesses:

  • PlayerProcess.destroy() closes stdin and sends SIGKILL to the subprocess.
  • disable() calls this._player?.destroy() and nulls it.
  • metadata.json declares "session-modes": ["unlock-dialog"], so the player
    only exists while locked.

I confirmed this empirically. Six lock/unlock cycles happened in five minutes
(PIDs 10455, 14454, 14772, 14988, 15167, 15373). The kernel's OOM task dump at
23:42:43 shows only PID 15373 alive — every earlier player was correctly
reaped. No process leak, no fd leak that I could see.

The two patterns that seem to provoke it

1. Pipeline churn. Six create/destroy cycles of a GPU video pipeline in five
minutes. First OOM followed twelve minutes later.

2. Sustained looped playback. The second OOM came after PID 15373 had been
decoding and compositing continuously for 12.8 hours — screen locked
overnight, background-video-looped on. This is where unblank matters:
without it the display would blank and presumably reduce the work; with it, the
pipeline runs flat out all night.

Concretely, that run was:

  • A 75-second 3840x2160 60 fps H.264 file
  • Looped via seek_simple on EOS, so roughly 613 flushing seeks
  • Roughly 2.76 million frames decoded and presented

Worth knowing, and possibly worth a line in your README: during both crashes
playbin was autoplugging a software decoder (openh264dec, rank
marginal), so 4K60 was being chewed by the CPU and then uploaded per-frame to
the GPU.

The cause turned out to be a stale GStreamer plugin registry
(~/.cache/gstreamer-1.0/registry.x86_64.bin). It had been generated at the
exact minute the NVIDIA driver was installed, before libcuda.so.1 existed, so
nvcodec was cached as having 0 features with the warning CUDA library "libcuda.so.1" was not found. It never re-probed. Deleting the cache fixed it —
nvh264dec now registers at rank primary + 1 (257).

This is not your bug either, but it will silently hit any user who installs your
extension around the same time as a GPU driver, and the symptom is just "the
lock screen is heavy". A troubleshooting line suggesting
rm ~/.cache/gstreamer-1.0/registry.*.bin might save people some confusion.

Possible mitigations on your side

Offered as suggestions, not demands — the real fix belongs in the driver.

  1. Idle timeout. After N minutes locked with no input, pause the pipeline
    (you already have _player.pause() wired up for prepare-for-sleep) or tear
    it down and show a static frame. Nobody is watching an animated background at
    4 a.m., and it would cap the exposure for everyone on NVIDIA.

  2. Pause on blank. Hook the screen-blank signal the same way you hook
    prepare-for-sleep. Users running unblank won't benefit, but most will.

  3. README note. A line about NVIDIA proprietary/open driver + long lock
    sessions, until the driver is fixed. Would save the next person the two days
    I spent reading OOM dumps.

  4. Cycle debounce. Rapid lock/unlock currently spawns a fresh GStreamer
    pipeline each time. A short grace period before teardown would collapse the
    churn case.

Happy to test

I have a reliable-ish reproduction environment and I am glad to test patches,
try settings combinations, or collect more kernel data. Just say what would
help.

oom-evidence-trimmed.txt
system-info.txt

Metadata

Metadata

Labels

bugSomething isn't workinghelp wantedExtra attention is needed

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions