Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WeakRef leaks memory, eventually causes (core dumped) #39902

Closed
dapplion opened this issue Aug 26, 2021 · 3 comments
Closed

WeakRef leaks memory, eventually causes (core dumped) #39902

dapplion opened this issue Aug 26, 2021 · 3 comments
Labels
v8 engine Issues and PRs related to the V8 dependency.

Comments

@dapplion
Copy link

Version

v16.8.0

Platform

Linux lion-gram 5.4.0-64-generic #72~18.04.1-Ubuntu SMP Fri Jan 15 14:06:34 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux

Subsystem

No response

What steps will reproduce the bug?

Run this script

while (true) {
  new WeakRef({});
}

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

Always

What is the expected behavior?

After each loop the newly created object {} should get garbage collected. Eventually the weak ref to that object should get garbage collected too. So the application should run forever with memory increasing and decreasing as gc kicks in.

What do you see instead?

The process memory increases linearly until ~2.5GB then crashes with

$ node oom.js


#
# Fatal error in , line 0
# Check failed: (location_) != nullptr.
#
#
#
#FailureMessage Object: 0x7ffcce0ed040
 1: 0xb6ef91  [node]
 2: 0x1bd8004 V8_Fatal(char const*, ...) [node]
 3: 0xeb772f v8::internal::Heap::KeepDuringJob(v8::internal::Handle<v8::internal::JSReceiver>) [node]
 4: 0x12239ec v8::internal::Runtime_JSWeakRefAddToKeptObjects(int, unsigned long*, v8::internal::Isolate*) [node]
 5: 0x15cdf39  [node]
Trace/breakpoint trap (core dumped)

Additional information

Analyzing the issue further seems that any object passed to the constructor of WeakRef is hold forever. I have other examples that cause an OOM with WeakRef usage:

Example with logs to visualize linear memory growth until OOM

let i = 0;
const heapUsed = process.memoryUsage().heapUsed;

while (true) {
  const arr = [];
  for (let i = 0; i < 1e7; i++) arr.push(i);
  new WeakRef(arr);

  global.gc();
  console.log(i++, (process.memoryUsage().heapUsed - heapUsed) / 1e6, "MB");
}
@devsnek
Copy link
Member

devsnek commented Aug 26, 2021

Please report this upstream to V8: https://bugs.chromium.org/p/v8

@devsnek devsnek closed this as completed Aug 26, 2021
@devsnek devsnek added the v8 engine Issues and PRs related to the V8 dependency. label Aug 26, 2021
@dapplion
Copy link
Author

dapplion commented Aug 26, 2021

@devsnek have you or any NodeJS developers seen alarming behaviour with WeakRefs since it has been introduced?

@dapplion
Copy link
Author

So this issue is expected an compliant with the specs. From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakRef#notes_on_weakrefs

If your code has just created a WeakRef for a target object, or has gotten a target object from a WeakRef's deref method, that target object will not be reclaimed until the end of the current JavaScript job (including any promise reaction jobs that run at the end of a script job)

So to prevent causing an OOM, let the event loop tick:

while (true) {
  new WeakRef({});
  await Promise(r => setTimeout(r, 0))
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
v8 engine Issues and PRs related to the V8 dependency.
Projects
None yet
Development

No branches or pull requests

2 participants