1

I'm working on a library that has:

  • Some fairly complex cyclical references.
  • Registers a variety of event listeners.
  • Uses some (singleton-style) objects for global caches

These properties mean that a bunch of stuff in my application are unlikely to be automatically garbage collected.

If the last reference of an object gets garbage collected, I would like to also automatically de-register event handlers, increasing the chances of larger potions of the library can get garbage collected.

In PHP it's possible to use a __destruct method for this purpose. Is there a similar mechanism possible in Javascript?

Broadly speaking, this would be a fictional example of my dependency graph:

Parent
  - childA
  - childB

Parent in this scenario only has outside references, so Javascript can GC this object if it's no longer used, but when this happens, I would like Parent to inform both childA and childB that they can de-register their event handlers and do additional cleanup.

Of course I could add a release() or destroy() method on the parent, but I would like this to work without requiring the end-user to explicitly signal the parent.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
Evert
  • 93,428
  • 18
  • 118
  • 189
  • 1
    You are looking for [weak references](https://github.com/tc39/proposal-weakrefs) and their finalizers. See also https://v8.dev/features/weak-references. But for now, `release()` seems to be your best bet. – Bergi Jan 21 '20 at 23:56
  • @Bergi wanna turn that into an answer? It works for me! – Evert Jan 22 '20 at 00:06
  • Ah, i didn't notice at first you were working in nodejs, which of course is better suited to use experimental features. – Bergi Jan 22 '20 at 00:12

2 Answers2

1

If the last reference of an object gets garbage collected, I would like to also automatically de-register event handlers, increasing the chances of larger potions of the library can get garbage collected.

You are looking for weak references and their finalizers. The event handler would not keep a direct reference to the instance, but only a weak one. When the instance is getting garbage-collected, the finalizer can unregister the event handler.

See also https://v8.dev/features/weak-references. I don't see any statement about node.js supporting this already, though.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
0

According to this SO question and this v8 blog node.js does not do reference counting but instead a full mark-and-sweep style of garbage collection.

This means that the garbage collector starts at the execution frame and the global object, and traverses all references, marking them as reachable. After it's done, it marks all regions of memory that were not reachable as "free space". Even if your library has a large amount of cyclical references and event listeners, if the whole block of references/the event emitter itself isn't reachable, all of it will get chucked by the mark and sweep.

You should typically have little to worry about as v8's garbage collector is rather robust, but it still pays to be conscious of releasing references that aren't needed anymore when needed (or ensuring a short lifetime of references or other such techniques).

Klaycon
  • 10,599
  • 18
  • 35
  • There's going to be bits in my code that will not ever trigger with this method unfortunately. Specific example, i have some events triggering on certain user actions. From a GC perspective, there definitely is still a global reference to these objects, so they don't actually ever get GC'd. – Evert Jan 21 '20 at 23:38