Skip to content

Significant heap usage regression in Node 22.19.0 #59733

Description

@michaelsmithxyz

Version

v22.19.0

Platform

Darwin ZG-F3FWLW4DJJ 24.6.0 Darwin Kernel Version 24.6.0: Mon Jul 14 11:28:30 PDT 2025; root:xnu-11417.140.69~1/RELEASE_ARM64_T6030 arm64

Subsystem

No response

What steps will reproduce the bug?

Node 22.19.0 uses significantly more heap memory than 22.18.0. I think it's because of this change, which introduces a cache for package.json metadata. Some packages are structured in such a way that this cache ends up quite large. The reproduction provided here uses date-fns, which exhibits this clearly.

To reproduce, compare heap snapshots for a script like this:

{
  "dependencies": {
    "date-fns": "^4.1.0"
  }
}
const http = require('node:http');
const {
  formatISO,
} = require('date-fns');

const server = http.createServer((req, res) => {
  if (req.method === 'GET') {
    res.writeHead(200);
    res.write(`${formatISO(new Date())}\n`);
    res.end();
  }
});

server.listen(3000);

In my testing, the total heap size for this script on 22.18 is ~7.2 MB, whereas on 22.19 it's ~28.9 MB. This was originally detected in a medium size application where an upgrade to 22.19 ballooned heap usage by more than 50 MB. Inspecting a heap snapshot shows that much of this increase is accounted for by objects retained by nearestParentPackageJSONCache

How often does it reproduce? Is there a required condition?

It reproduces consistently on 22.19.0

What is the expected behavior? Why is that the expected behavior?

I would not expect such a significant increase in heap usage

What do you see instead?

A significant increase in heap usage

Additional information

A zip containing heap snapshots for the reproduction script is attached

HeapSnapshots.zip

Activity

  1. nLeichtle commented on Sep 3, 2025

    @nLeichtle

    I can confirm the behaviour. Memory consumption more than doubled.
    Downgrading to 22.18 reduces back to "normal" memory size.

  2. michaelsmithxyz commented on Sep 3, 2025

    @michaelsmithxyz
    ContributorAuthor

    In case it's helpful for others: in our application at least, switching to date-fns single-function imports (e.g. import { isValid } from 'date-fns' -> import { isValid } from 'date-fns/isValid') reduced the magnitude of the heap increase significantly, so it does seem pretty package specific. That said, while this workaround works in this specific case, the size of this cache in memory still seems way too big.

  3. BridgeAR commented on Sep 8, 2025

    @BridgeAR
    Member

    I looked at the code how the original cache worked and how the new cache works and just by reading the code it seems to roughly contain the same data (now a nested object).
    Could you check how much memory it used to use with Node.js 20? It was released in Node.js 21.5 and all 22 and onwards also contain the change with the C++ implementation.

  4. added
    loadersIssues and PRs related to ES module loaders.
    on Sep 8, 2025
  5. michaelsmithxyz commented on Sep 8, 2025

    @michaelsmithxyz
    ContributorAuthor

    @BridgeAR Here are some data points for the reproduction in the original message:

    1. 20.19.5 - ~5.6 MB heap, ~48 MB RSS
    2. 21.5.0 - ~5.6 MB heap, ~49 MB RSS
    3. 22.18.0 - ~6.3 MB heap, ~54 MB RSS
    4. 22.19.0 - ~28 MB heap, ~76 MB RSS
  6. michaelsmithxyz commented on Sep 8, 2025

    @michaelsmithxyz
    ContributorAuthor

    @BridgeAR I think the big difference between the previous JS-side cache (the one removed in #50322) and the one introduced here is that the original cache was a map from package.json path to deserialized package.json metadata, whereas this is a map from any module file path to deserialized package.json metadata. This duplicates cache data when multiple module files share the same parent package.json file. This is obviously common in general, but there are also some degenerate cases like date-fns which have a ton of paths and a relatively large package.json metadata object

  7. FelipeEmerim commented on Sep 9, 2025

    @FelipeEmerim

    Just adding to the discussion, something has definitely changed in regards to memory between Node.JS 22.18 and 22.19. We have started seing 139 exit codes on the startup process of many applications and the increased heap usage mentioned. Downgrading to NodeJS 20 or 22.18 "fixes" the issue for us.

  8. mqdeandrade commented on Sep 10, 2025

    @mqdeandrade

    Same in our team, we have seen an increase of 100MB across most of our apps.
    A previous commentor mentioned date-fns, we definitely use that library and it might be responsible for the larger than average increase. Will report back if I manage to do some testing with and without.

  9. BridgeAR commented on Sep 12, 2025

    @BridgeAR
    Member

    @michaelsmithxyz that sounds right. Since you already looked into the issue, would you mind opening a PR to fix that?

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

    loadersIssues and PRs related to ES module loaders.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions