devtools icon indicating copy to clipboard operation
devtools copied to clipboard

fix: devtools is causing a severe memory leak

Open mjlehrke opened this issue 1 year ago • 27 comments

🐛 The bug

Creating a bare Nuxt project with npx nuxi@latest init project and starting it with npm run dev causes severe memory leak (most of the time). This happens on Windows with Node v22+. This happens on a bare Nuxt starter with no additional Nuxt modules or npm packages added. Importantly, the memory leak occurs without any incoming requests happening or the app open in a browser. You only need to npm run dev after doing the nuxi project init and it will start leaking immediately. This is going to be a pain in the ass because I noticed it usually doesn't happen on the first run of npm run dev but if you stop the dev server and run the command again it will happen (you know you have it when the CPU is high and the memory starts incrementing).

I believe this is different than https://github.com/nuxt/nuxt/issues/30164 as that is in a built project with requests.

Observations:

  • It does not leak when building and running npm run preview.
  • Requests to the dev server are not needed to leak memory.
  • Disabling devtools prevents the memory leak.
  • It does not leak every time the dev server is started, maybe 10% of the time it will run normally on the bare project.
  • It also leaks with Node v22.12.0 in addition to v23.3.0.
  • Abnormally high CPU usage is occurring.
  • It ticks up by 2.7-2.9 MB per second.

Proof

These images were taken after enabling/disabling Nuxt devtools and running npm run dev and waiting for exactly 5 minutes.

devtools: { enabled: true } Image

devtools: { enabled: false} Image

Snapshots

These make it seem like there is something with \node_modules\unstorage\node_modules\readdirp\index.js and/or are-we-there-yet\node_modules\readable-stream. But also defineNuxtSchema.

Here's how I did this:

  1. npx nuxi dev --inspect with devtools disabled
  2. Open Chrome and go to chrome://inspect and inspect the Node project
  3. Let it run 5 minutes, collect garbage and take another snapshot (Snapshot 1, control)
  4. Edit nuxt.config.ts and enable devtools, let it restart with HMR
  5. Let it run 10 minutes, then collect garbage and take another snapshot (Snapshot 2)
  6. Let it run 10 more minutes, then collect garbage and take final snapshot (Snapshot 3)

Snapshot 2 vs Snapshot 3 (devtools enabled short vs longer leak) Image Image Image Image Image Image

Full reproduction

Since I don't think stackblitz is going to show this issue:

  1. npx nuxi init@latest project
  2. cd project
  3. npm run dev
  4. Quit the process and re-run npm run dev
  5. Observe memory leak
  6. npx nuxi devtools disable
  7. npm run dev
  8. Observe no memory leak

🛠️ To reproduce

https://stackblitz.com/edit/github-4exzk3tl

🌈 Expected behavior

devtools should not be causing a memory leak in a bare project created with npx nuxi@latest init project

ℹ️ Additional context

npx nuxi info

  • Operating System: Windows_NT
  • Node Version: v23.3.0
  • Nuxt Version: 3.14.1592
  • CLI Version: 3.16.0
  • Nitro Version: 2.10.4
  • Package Manager: [email protected]
  • Builder: -
  • User Config: default
  • Runtime Modules: -
  • Build Modules: -

Full nuxt.config.ts (devtools enabled)

// https://nuxt.com/docs/api/configuration/nuxt-config
export default defineNuxtConfig({
  devtools: {
    enabled: true,
    timeline: { enabled: true },
  },

  compatibilityDate: '2024-11-01',
})

Full nuxt.config.ts (devtools disabled)

// https://nuxt.com/docs/api/configuration/nuxt-config
export default defineNuxtConfig({
  devtools: {
    enabled: false,
    timeline: { enabled: true },
  },

  compatibilityDate: '2024-11-01',
})

mjlehrke avatar Dec 09 '24 06:12 mjlehrke

Hey Michael, thanks a lot for the detailed investigation of the issue.

First of all, I would love to have a consensus about the definition of "Memory Leak", could you explain a bit of your interopation here?

To me, I think a memory leak is about a long-running production server that holds stable data from requests/loops that make the memory grow consistently and eventually hit the physical limit causing the crash. While in a way, I don't even think the concept applies to dev servers as they are not designed to be long-running. From what I read of your repo, I didn't see the memory growing over time (isn't Snapshot 2 & 3 has the same memory cost?), tho I agree it indeed consumes more memory - but that sounds reasonable to me and isn't really a "memory leak".

There are multiple reasons DevTools would cause more memory:

  • The fact that DevTools collects data and stores it in the memory for easier investigation
  • Additional transform plugins to inject anchor/debug points (https://github.com/webfansplz/vite-plugin-vue-inspector)
  • https://github.com/antfu-collective/vite-plugin-inspect would store the entire transform history of each module
  • The timeline: true feature (it's still experimental), add additional wrappers to auto imported functions to collect the data
  • ...

I am not an expert of this for sure, so feel free to point out anything I might be wrong about. I'd also love to hear more context of your side of the story, like why you are looking into this and what troubles you, etc.

Thanks!

antfu avatar Dec 09 '24 15:12 antfu

Hey Anthony,

Sorry I should have been more clear. The memory consumption continues to grow over time until it crashes, not just a one time bump with the devtools enabled. I was looking into this because of my dev environment crashing. At first I thought it was due to something in the Nuxt app I was working on. At first I tried removing modules to try and pinpoint it with no success. I flipped the approach and tried to start with a fresh Nuxt init and slowly add modules from there, but I noticed right away that the problem was occurring in the newly initialized Nuxt app!

This was my first time capturing snapshots (and I only dev as a hobby). The size in the snapshot is not the memory consumption, I think that is the size of the snapshot data itself. If I download the snapshot data the file sizes are what was indicated in the screenshots.

But I would consider this a memory leak. If I leave the dev server running for about 2 hours while I'm working it will crash the Node process (and VSCode) when my machine runs out of memory. To mitigate this I've been restarting the Nuxt dev server frequently.

So I guess to better describe the images under the "proof" section. Without devtools enabled the bare Nuxt app uses about 230 MB of memory. Enabling devtools, it will immediately jump to ~800 MB of memory usage and then grow from there. In the screenshot with devtools enabled that was running for 5 minutes, it was already up to 1233 MB memory usage. I did try testing with timeline: true disabled and it still occurs.

I have 16 GB in my machine, and it will continue to grow until it crashes.

mjlehrke avatar Dec 10 '24 03:12 mjlehrke

Downgrade to node v22.11.0 can be another workaround instead of disabling devtools.

kingyue737 avatar Dec 11 '24 03:12 kingyue737

Downgrade to node v22.11.0 can be another workaround without disabling devtools.

That's interesting. @kingyue737 Do you have any more details to share why Node version would make a difference here?

antfu avatar Dec 11 '24 06:12 antfu

Just FYI the node versioning system is weird and for all intent and purposes node 22 should not be considered a downgrade over 23 because 22 is the LTS and the odd number (23) is not considered stable AKA the beta

In the snapshot I see windows, do you also get a leak on linux?

It might be a memory leak in node 23 with windows

Tofandel avatar Dec 12 '24 13:12 Tofandel

@Tofandel Not only v23, the latest v22.12.0 on Windows also has this issue. That’s why I propose a “downgrade”

kingyue737 avatar Dec 12 '24 17:12 kingyue737

I see, I thought you meant only downgrade from node v23

In this case having a look into the commit history of node to find the culprit might be a good idea

Especially around those [c17601557b] - fs: prevent unwanted dependencyOwners removal (Carlos Espa) https://github.com/nodejs/node/pull/55565 (the most likely culprit given that this seems to be a file watcher issue) [5357338b8e] - fs: use wstring on Windows paths (jazelly) https://github.com/nodejs/node/pull/55171

If you know how, maybe try to checkout node in v22.12.0 and start reverting commit, build and start nuxt with the built node until you see the memory leak gone so we can identify the culprit

Tofandel avatar Dec 13 '24 16:12 Tofandel

I also see an increase of 200Mb of memory use on every nuxt reload in node 22.12.0 in linux but not in 22.11.0

So node issue and not specific to windows. I'll try to see without the commit I suspect to see if this is the culprit

Tofandel avatar Dec 13 '24 16:12 Tofandel

I can confirm the the bug is introduced between node v22.11.0 and v22.12.0. 22.11.0 has stable memory usage with devtools on while 22.12.0 has the memory leak.

mjlehrke avatar Dec 14 '24 22:12 mjlehrke

This was a fun learning experience. I methodically built node commits between v22.11.0 and v22.12.0 and tested them to narrow in on the culprit.

I identified https://github.com/nodejs/node/commit/41c50bc15e36836538ccbe54f00de5658b4cafa8 as the commit that introduces the memory leak. Unfortunately, that commit introduces a lot of changes so hard to narrow in.

This is 100% out of my expertise, if someone else wants to confirm this is the commit.

I wonder if this might be related, it is already fixed in the upstream libuv https://github.com/nodejs/node/issues/52769 https://github.com/nodejs/node/pull/56243

mjlehrke avatar Dec 15 '24 05:12 mjlehrke

If you suppress the noise in the update which are tests doc change and platform specific changes. The changes become minimal.

I find the changes in uv__stream_recv_cmsg a bit suspicious, they are tingling my developer senses, can you try to test with just the changes in this function reverted?

We'll need to open an issue in the libuv repo once we find the cause

Tofandel avatar Dec 15 '24 08:12 Tofandel

I reverted the changes to uv__stream_recv_cmsg in deps/uv/src/unix/stream.c but it still leaked.

mjlehrke avatar Dec 16 '24 03:12 mjlehrke

Got it!

The minor logic update in deps/uv/src/win/fs-event.c introduces the memory leak. When I revert this change it no longer leaks memory. I do not know C, so this is above my pay grade for next steps.

https://github.com/nodejs/node/pull/55114/files#diff-f0e94526ff1778190e753978e54f805b05a9c1c2851f261375ffb01b4935918b

mjlehrke avatar Dec 16 '24 04:12 mjlehrke

Seems it might already have been fixed https://github.com/libuv/libuv/pull/4647

Edit: maybe different memory leak, reported on an earlier version. But try the fix anyways as maybe the fix to the function now makes it so it goes in where the other memory leak is

Tofandel avatar Dec 16 '24 06:12 Tofandel

@mjlehrke Thanks for investigating and finding the cause of the leak

A PR has been merged that should fix it https://github.com/libuv/libuv/pull/4656

It might take a month or so until node picks it up though, so you may want to build node yourself with the patch for now and use that built version to avoid the memory leak

Though I will have to investigate why it's leaking on linux as well then as there must be yet a different memory leak somewhere

Tofandel avatar Dec 16 '24 12:12 Tofandel

Sounds good, closing this in anticipation of the upstream fix.

mjlehrke avatar Dec 17 '24 22:12 mjlehrke

I feel this should stay open until a fixed version is available, is there a resolution other than downgrading node?

sjrc6 avatar Feb 22 '25 08:02 sjrc6

libuv fixed this in v1.50.0 https://github.com/libuv/libuv/releases/tag/v1.50.0

And Node picked up libuv v1.50.0 in v23.7.0 at least https://github.com/nodejs/node/releases/tag/v23.7.0

mjlehrke avatar Feb 23 '25 02:02 mjlehrke

But failed to backport to v22 LTS https://github.com/nodejs/node/pull/56616#issuecomment-2638332801. For those who use Node v22, we still need to stay at v22.11.0

kingyue737 avatar Feb 26 '25 07:02 kingyue737

~~Unfortunately, I'm still experiencing this with Node 23.9.0~~ EDIT: attempted reinstall, works with Node 23.9.0 now

JakeIsMeh avatar Mar 02 '25 01:03 JakeIsMeh

Still happening on LTS node. Why is this a closed issue ?

Brakkar avatar Mar 09 '25 09:03 Brakkar

Re-opening

Still happening on LTS node. Why is this a closed issue ?

Because the bug was introduced in Node. There is nothing Nuxt can do to alleviate this problem. But I can re-open this to keep track of the issue.

mjlehrke avatar Mar 10 '25 01:03 mjlehrke

Still happening on LTS node v22.16.0.

Quang-Dong avatar May 29 '25 09:05 Quang-Dong

Tried Node V25 nightly. Memory issue is gone but CPU still busy

hexadecimal233 avatar May 31 '25 03:05 hexadecimal233

It’s still happening with v22. v20 is working pretty well.

ashomurodov avatar Jun 18 '25 05:06 ashomurodov

Currently I tried with list version , them work reduce memory leak

  • Node v20.19
  • Vue 3.5.13
  • Nuxt 3.11.1

voratham avatar Jun 25 '25 04:06 voratham

I tried v22.17.0. It seems fixed

kingyue737 avatar Jun 29 '25 14:06 kingyue737