Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to ensure wasm memory is freed when using it from JavaScript

I have a C library that looks like this:

struct timeseries *ts_create(void) {
    /* Allocate some memory and return a pointer. */
}

void ts_free(struct timeseries *p) {
    /* Free the memory block pointed to by p. */
}

/* And many other functions that receive a struct timeseries * and
 * do things to it.
 */

I've compiled this with emscripten and I'm creating a JavaScript interface (wrapper) to it, like this:

const timeseries = {
  ptimeseries: 0,

  initialize() {
    this.ptimeseries = cfunctions.ts_create();
  },

  destroy() {
    cfunctions.ts_free(this.ptimeseries);
  },

  // And many other functions
}

You could use it like this:

const myTimeseries = Object.create(timeseries);
try {
  myTimeseries.initialize();
  // do more things
} finally {
  myTimeseries.destroy();
}

The problem is that I'd like to keep the "dangerous" stuff, i.e. the memory allocation and freeing, in C (or in the JavaScript wrapper), so that the JavaScript programmer can use the resulting library safely. JavaScript programmers are used to objects freeing themselves automatically, and requiring them to add some kind of try ... finally statement is error prone.

But as far as I can see JavaScript doesn't have any object destructors or any kind of onGarbageCollect(object) event.

What can I do about this?

like image 622
Antonis Christofides Avatar asked Oct 28 '25 04:10

Antonis Christofides


1 Answers

There is a new JavaScript feature known as FinalizationRegistry which you can use for this functionality, but note that it is not yet supported across all browsers (https://caniuse.com/mdn-javascript_builtins_finalizationregistry)

const registry = new FinalizationRegistry((heldValue) => {
  cfunctions.ts_free(heldValue);
});

class Timeseries {
  constructor() {
    this.ptimeseries = cfunctions.ts_create();
    registry.register(this, this.ptimeseries, this);
  }

  destroy() { // manual destructor for backup, you don't have to call this
    registry.unregister(this);
    cfunctions.ts_free(this.ptimeseries);
  }
}
like image 134
snek Avatar answered Oct 30 '25 19:10

snek