Skip to content

[WPE 2.38] Possible memory leak or GC not working #1569

Open

Description

@gnulux

Hi [Recipient Name],

I am currently running cog 0.12.3 with Webkit 2.38.6 on an IMX8plus ​ARM64 Yocto embedded system, displaying a JavaScript page generated from ReactJS.

A few months ago, I updated my Yocto meta-webkit to use WebPlatformForEmbedded/WPEWebKit wpe-2.38. I configured the following memory limitation variables:

WPE_POLL_MAX_MEMORY="databaseprocess:10m,networkprocess:5m,webprocess:140m,rpcprocess:10m"
WPE_RAM_SIZE="182m"

After restarting cog, the WPEWebProcess initially operates as expected, keeping memory usage below 180MB, and I can observe garbage collection (GC) reclaiming memory in the logs. However, if I leave my application open on COG for approximately seven days without any screen operations, I notice a continuous increase in WPEWebProcess memory consumption, as shown in the graph below. It appears that the GC stops functioning during this period.

Image

Could you please advise on how I can effectively monitor what is causing this progressive memory growth?

Activity

  1. justinmichaud commented on Oct 8, 2025

    @justinmichaud

    Does this just happen on your app? Or do you experience it on other sites too? Please also try disabling JIT, to see if you observe the same trend. You can do that by setting the environment variable JSC_useJIT=0. Confirm that your settings are working with JSC_validateOptions=1 JSC_invalidAndShouldCrash=1

  2. gnulux commented on Oct 9, 2025

    @gnulux
    Author

    Hi ,
    The issue seams to be related to my app but i didn't validate on another website or app .
    Contrary to what I mentioned in my last update, the application is actively being used via the touchscreen when the leak occurs.
    I have configured the following settings: JSC_useJIT=0, JSC_validateOptions=1, and JSC_invalidAndShouldCrash=1 and my application still works . I will provide an update on the trend in a few days.

  3. justinmichaud commented on Oct 9, 2025

    @justinmichaud

    my application still works

    This means the settings aren't being applied unfortunately, it should crash

  4. gnulux commented on Oct 10, 2025

    @gnulux
    Author

    Hi,

    You mean the process should crash at start ?
    This is the command i pass on command line :
    JSC_useJIT=0 JSC_validateOptions=1 JSC_invalidAndShouldCrash=1 COG_PLATFORM_WL_VIEW_FULLSCREEN=1 COG_URL=http://127.0.0.1:8080 /usr/bin/cog -P wl

    The same command with JSC_logGC=1 , show GC output in journalctl -xf -u cog
    And the application start normally

  5. justinmichaud commented on Oct 10, 2025

    @justinmichaud

    I guess if logGC works, it is probably fine. Let's see if the memory usage changes

  6. gnulux commented on Oct 13, 2025

    @gnulux
    Author

    Hi ,

    Following the activation of JSC_useJIT=0 last Friday, we've observed a complete reversal in memory consumption. The current trend now shows a significant reduction in memory usage, as illustrated in the attached graph

    Image
  7. justinmichaud commented on Oct 13, 2025

    @justinmichaud

    Fun! This is great, I know what your problem is: we just keep tiering up new jit code.

    We have discussed adding API to turn off jitting after a while. There are tons of things that can be done about this, but it is a bit of ways off and requires some deep thought.

    So for now: maybe try setting JSC_jitMemoryReservationSize to something small, and measure the memory/performance of your application?

    It is also worth noting that since this is JIT code and you need the memory, you can always ask nicely for the vm to release it. If you compile with developer mode enabled and run with JSC_useDollarVM=1, you can run:

    $vm.triggerMemoryPressure()
    

    in your application code. This should reduce your memory usage, and if it doesn't, it is totally a bug that we need to fix.

    *** Developer mode / dollarVM is very dangerous for production, it is just for testing ***

    If that works, perhaps we need to make some memory pressure API.

  8. gnulux commented on Oct 13, 2025

    @gnulux
    Author

    Understood , but i have several devices in production and i'm wondering if it is safe to only disable JIT ? or do i have to set JSC_jitMemoryReservationSize. Regarding my last tests it seems to work fine without JIT and consume less memory than before.

  9. justinmichaud commented on Oct 14, 2025

    @justinmichaud

    If you are fine with the decreased performance, it is totally safe to disable JIT

  10. gnulux commented on Nov 27, 2025

    @gnulux
    Author

    Hi,

    Coming back on my issue not fully resolved yet

    Almost all my devices works pretty well except two of them when the memory still growing in a day.
    JIT is still disabled.
    We've added a routine in order to restart cog when memory goes up to 250M (see bellow).

    Image

    Nothing weird appears from the inspector
    I think i have to analyse JavascriptCore behaviour but how can i dump Webkit heap into a file ?

  11. justinmichaud commented on Nov 27, 2025

    @justinmichaud

    Is there anything different about the two devices? Are they all running the same page? Are you certain that they aren't jitting? You can run with JSC_dumpDisassembly=1 to be sure (try with and without JIT to confirm your options are being applied).

    The first thing I would try is to manually gc. If manually gcing fixes your issue, we can look into options for lowering the gc threshold. Running $vm.triggerMemoryPressure() and $vm.gc in your JS should do this.

    Then, it would be nice to confirm there is no JS memory leak (ex: appending some object to Window)

    You can use remote WebInspector to analyze the JS heap, and you can build with system malloc (see the cmake option) to use something like HeapTrack to look at the WebKit native heap.

    Alternatively, if you have a case that easily reproduces this issue in Epiphany on the desktop, I can take a look.

    For WebInspector, I have some notes that may or may not be helpful: https://github.com/justinmichaud/justinmichaud.github.io/wiki/Building-WPEWebKit-for-32%E2%80%90bit-Raspberry-Pi-3-(Buildroot-DRM-config)#pi-webinspector

  12. gnulux commented on Nov 28, 2025

    @gnulux
    Author

    ​All the devices have the same image with same application and following cog settings
    WPE_POLL_MAX_MEMORY="databaseprocess:10m,networkprocess:5m,webprocess:140m,rpcprocess:10m"
    WPE_RAM_SIZE="182m"
    JSC_useJIT=0

    The two devices are in production so I need customer validation first before to change the settings but on my integration device (same apps, version, and settings) when I enable JSC_dumpDisassembly=1 and JSC_useIJIT is commented I can see outputs in the console.

    We will see if we can add triggerMemoryPressure() in our code.

    For the WebInspector , it does not show the Memory tab on my version of Epiphany 48 Weird!!
    Unfortunately I can not reproduce this behaviour on my device or on a desktop with Epiphany. The issue occurs only on the production environment.
    For now , I should only be able to connect to WebIn​spector on these devices.
    In the meanwhile , I'm preparing a new image with heaptrack and Webkit build with cmalloc.
    Also found this link https://blogs.igalia.com/plampe/tracking-webkit-s-memory-allocations-with-malloc-heap-breakdown/ is it avalaible in 2.38 already ?

    Your previous link is very usefull by the way , thks

  13. justinmichaud commented on Nov 28, 2025

    @justinmichaud

    cc @Scony re: heaptrack

    This does seem like a head scratcher if it doesn't reproduce on desktop epiphany. Your integration device doesn't reproduce this trend either?

    What commit of 2.38 are you on?

  14. gnulux commented on Nov 28, 2025

    @gnulux
    Author

    I'm on the latest commit of wpe-2.38 branch (Building from Yocto recipe).
    git://github.com/WebPlatformForEmbedded/WPEWebKit.git;protocol=https;branch=wpe-2.38

    I do not reproduce the trends on integration device. To be more precise the device is connected to extenal industrial equipments and receive trafic that I cannot fully simulate on integration. Furthermore FS in production are readOnly but COG env variables can be modified.

    Does your need is that Epiphany shows the same content than COG ? I think i can do this with port-redirect but not sure .

  15. justinmichaud commented on Nov 29, 2025

    @justinmichaud

    My guess is: if this can't be reproduced with epiphany or with the integration device, and if your production device has the commits from October, then there might be something going on with your app.

    The content is very important. It is also important to rule out any JS memory leaks (such as appending data to an array, but never clearing it).

    Please confirm that the production device has the commits from October. "Exclude non-user portions of the main thread stack from stack scanning on 32 bits." fixes a similar issue.

  16. gnulux commented on Dec 1, 2025

    @gnulux
    Author

    Regarding the commit i'm running on a 64bits node (IMX8M Plus). Seems the patch was mainly for 32bits . right ?
    My apologies, i just noticed that we were on fixed commit 59d63a5.
    Sorry again , I'm going to build latest commit and will see the trend on production environment.

  17. gnulux commented on Dec 1, 2025

    @gnulux
    Author

    Now on commit 3c84c7a the trend goes worst on my integration node.
    Build with cmalloc :
    EXTRA_OECMAKE_append_pn-wpewebkit = " -DUSE_SYSTEM_MALLOC=ON -DCMAKE_BUILD_TYPE=Debug"

    WPE_RAM_SIZE has no more effect . The memory starts at 200M and goes up until my node crash and reboot
    Same behavoiur with or without JIT.

    Image

    $vm does not seams to be available i have folowing error at Cog start.
    WARNING: failed to parse JSC_useDollarVM=1

    Environment options :
    WPE_RAM_SIZE='200mb'
    JSC_jitMemoryReservationSize=33554432
    WEBKIT_DISABLE_SANDBOX_THIS_IS_DANGEROUS=1
    WEBKIT_INSPECTOR_HTTP_SERVER=0.0.0.0:9222
    JSC_validateOptions=1
    JSC_invalidAndShouldCrash=1
    JSC_useDollarVM=1
    JSC_enableStrongRefTracker=1
    JSC_dumpHeapOnLowMemory=0
    JSC_useSourceProviderCache=0
    JSC_useCodeCache=0
    JSC_useSamplingProfiler=1
    JSC_samplingProfilerPath=/data/tmp/

  18. justinmichaud commented on Dec 1, 2025

    @justinmichaud

    $vm does not seams to be available i have folowing error at Cog start.
    WARNING: failed to parse JSC_useDollarVM=1

    You need to build with DEVELOPER_MODE=ON in cmake. It is off by default because it is not safe for production.

  19. justinmichaud commented on Dec 1, 2025

    @justinmichaud

    If you can find a public reproduction case, that would be very helpful

  20. oaquique commented on May 27, 2026

    @oaquique

    Confirming JSC_useJIT=0 mitigation is effective on a different stack — adding
    data points in case useful for triage.

    Environment

    • Raspberry Pi 5 (4 GB) on NVMe, Debian 13 Trixie (aarch64)
    • cog 0.18.4-1+b1, libwpewebkit-2.0-1 2.50.6
    • Workload: single React 18 page (a kiosk clock with weather + calendar
      panels) at http://localhost:3000, runs continuously, never navigated
    • Invocation: cog --platform=drm --platform-params=renderer=gles,rotation=1
      (DRM platform, no compositor)

    Before JSC_useJIT=0

    • WPEWebProcess RSS grows linearly at ~30 MB/hr, sustained for hours
    • Verified over an 8.5-hour window: 25.2% → 30.3% on the 4 GB device
      (~230 MB delta, matches the rate band reported in this thread and in
      Cog memory leak Igalia/cog#65)
    • Mitigated externally by a 3 AM systemctl --user restart kiosk.service
      cron; peak before restart sits at ~42% of 4 GB

    After JSC_useJIT=0

    • Initial warmup (~90 min): some allocation as the app cycles through its
      first weather refresh, calendar fetch, panel transitions. cog+WPE
      RSS grows from 424 MB → ~440 MB during this window.
    • After warmup: memory plateaus. System-wide memory holds flat at 22% of
      4 GB across the entire 2-hour measurement window. Per-process RSS for
      WPEWebProcess: 222 MB → 237 MB → 236 MB at T0/T+90m/T+2h respectively.
    • Net: at least a 4× reduction in leak rate, and visually it appears the
      rate is approaching zero after warmup.

    Performance impact on our workload: negligible.
    WeatherKit + ICS calendars, React reconciliation of a small tree)

    • Animations are CSS, not JS-driven
    • System-wide CPU stable at 13-14% before and after the JIT-disable change
      (no measurable difference)
    • Confirms @justinmichaud's claim that JIT-off is "totally safe" for typical
      kiosk content

    Audited the React app code for common leak patterns before suspecting WPE:
    setInterval/setTimeout/addEventListener/AbortController calls all
    have paired cleanups; web worker is properly terminated; no
    requestAnimationFrame/MutationObserver/dynamic Image/AudioContext;
    useEffect dependency arrays correct. The app's not the source — this is
    genuinely a JIT-side allocation that isn't being reclaimed.

    Posting in case other folks hitting the same kiosk-on-WPE memory growth want
    another confirmation that the workaround works in production on current WPE.
    Happy to provide more diagnostics if useful (heap snapshots via remote
    inspector, JSC option matrix, etc.).

  21. justinmichaud commented on May 28, 2026

    @justinmichaud

    You can set a jit reservation limit which should give you a good compromise then. We need to think of a better way to handle tier-up over long timescales.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions