You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[WPE 2.38] Possible memory leak or GC not working #1569
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:
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.
Could you please advise on how I can effectively monitor what is causing this progressive memory growth?
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
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.
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
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
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.
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.
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).
Nothing weird appears from the inspector
I think i have to analyse JavascriptCore behaviour but how can i dump Webkit heap into a file ?
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.
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 WebInspector 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
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 .
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).
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.
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.
$vm does not seams to be available i have folowing error at Cog start. WARNING: failed to parse JSC_useDollarVM=1
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.).
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.
Activity
justinmichaud commentedon Oct 8, 2025
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
gnulux commentedon Oct 9, 2025
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, andJSC_invalidAndShouldCrash=1and my application still works . I will provide an update on the trend in a few days.justinmichaud commentedon Oct 9, 2025
This means the settings aren't being applied unfortunately, it should crash
gnulux commentedon Oct 10, 2025
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 wlThe same command with JSC_logGC=1 , show GC output in journalctl -xf -u cog
And the application start normally
justinmichaud commentedon Oct 10, 2025
I guess if logGC works, it is probably fine. Let's see if the memory usage changes
gnulux commentedon Oct 13, 2025
Hi ,
Following the activation of
JSC_useJIT=0last 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 graphjustinmichaud commentedon Oct 13, 2025
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:
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.
gnulux commentedon Oct 13, 2025
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.
justinmichaud commentedon Oct 14, 2025
If you are fine with the decreased performance, it is totally safe to disable JIT
gnulux commentedon Nov 27, 2025
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).
Nothing weird appears from the inspector
I think i have to analyse JavascriptCore behaviour but how can i dump Webkit heap into a file ?
justinmichaud commentedon Nov 27, 2025
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
gnulux commentedon Nov 28, 2025
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=0The 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 WebInspector 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
justinmichaud commentedon Nov 28, 2025
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?
gnulux commentedon Nov 28, 2025
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.38I 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 .
justinmichaud commentedon Nov 29, 2025
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.
gnulux commentedon Dec 1, 2025
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.
gnulux commentedon Dec 1, 2025
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.
$vm does not seams to be available i have folowing error at Cog start.
WARNING: failed to parse JSC_useDollarVM=1Environment 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/
justinmichaud commentedon Dec 1, 2025
You need to build with DEVELOPER_MODE=ON in cmake. It is off by default because it is not safe for production.
justinmichaud commentedon Dec 1, 2025
If you can find a public reproduction case, that would be very helpful
oaquique commentedon May 27, 2026
Confirming
JSC_useJIT=0mitigation is effective on a different stack — addingdata points in case useful for triage.
Environment
cog0.18.4-1+b1,libwpewebkit-2.0-12.50.6panels) at
http://localhost:3000, runs continuously, never navigatedcog --platform=drm --platform-params=renderer=gles,rotation=1(DRM platform, no compositor)
Before JSC_useJIT=0
(~230 MB delta, matches the rate band reported in this thread and in
Cog memory leak Igalia/cog#65)
systemctl --user restart kiosk.servicecron; peak before restart sits at ~42% of 4 GB
After JSC_useJIT=0
first weather refresh, calendar fetch, panel transitions. cog+WPE
RSS grows from 424 MB → ~440 MB during this window.
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.
rate is approaching zero after warmup.
Performance impact on our workload: negligible.
WeatherKit + ICS calendars, React reconciliation of a small tree)
(no measurable difference)
kiosk content
Audited the React app code for common leak patterns before suspecting WPE:
setInterval/setTimeout/addEventListener/AbortControllercalls allhave paired cleanups; web worker is properly terminated; no
requestAnimationFrame/MutationObserver/dynamicImage/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.).
justinmichaud commentedon May 28, 2026
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.