Skip to content

memory leak in shadow realms #47353

Open
@joyeecheung

Description

@joyeecheung

Version

all

Platform

all

Subsystem

shadow-realm

What steps will reproduce the bug?

// Flags: --experimental-shadow-realm --max-old-space-size=20
'use strict';

for (let i = 0; i < 1000; i++) {
  const realm = new ShadowRealm();
  realm.evaluate(`new TextEncoder(); 1;`);
}

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

Always

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

Shouldn't crash from OOM

What do you see instead?

Crash from OOM

Additional information

See analysis #47339 (comment). This was introduced in #46809. The current memory management of shadow realms requires that there should be no strong global references in the graph, but we currently have many of them in the code base - among them are the binding data and the aliased arrays associated with the encoding binding, which is lazily created when TextEncoder is accessed, for example.

I think we have at least two options:

  1. Change the memory management of shadow realms so that it doesn't rely on the context being GC'ed to GC itself (otherwise any out-of-band global reference to objects in that context holds the context alive forever) - I am not sure how feasible it is, superficially that seems plausible, because the shadow realms boundary ensures that no objects can be leaked out of the shadow realms, therefore once the shadow realms wrappers are unreachable the context should be unreachable, but it might get more complex once there's asynchronicity/modules involved
  2. Avoid making BaseObjects strong - there are strong BaseObjects everywhere in the code base, however, I am not sure if it's actually practical to simply eliminate all strong global references - we might end up having some of them just impossible to make weak, and they'll result in a leak once they end up in a shadow realm.

Or, we could use some help from V8 to get notified about the realms being unreachable, and release the realms in some callback instead of in a weak callback of the context. It's not clear to me what's enough for us at this point, though.

Metadata

Metadata

Assignees

No one assigned

    Labels

    memoryIssues and PRs related to the memory management or memory footprint.realmIssues and PRs related to the ShadowRealm API and node::Realm

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions