0

I have a WebAssembly instance which creates a WebGL2 context. Ideally, when exiting the part of the page showing the context, I'd like to destroy the context and let the module and the textures, etc. be garbage collected. Problem is, I can't track down what is retaining a reference to the WebAssembly object.

How do I identify all places (properties, closures) with a reference to this object? (Chrome devtools or other readily available tools)

Preston Garno
  • 1,175
  • 10
  • 33
  • You might try out or Google for docs/blogs on Chrome -> Developer Tools -> Memory a bit. "Heap snapshot" or "Allocation instrumentation on timeline" may get what you need. With "heap snapshot" you should be able to visualize refs to the object at a point in time. Or if you're not sure how to recreate the particular instant state/snapshot you want to examine, the latter "timeline" tool can help you identify possible leaks, and your object of concern may show up there. – Will Feb 18 '20 at 21:12
  • @WillCain I did read the docs. I might have prematurely asked this question, because it's starting to make sense after some trial and error – Preston Garno Feb 18 '20 at 21:20
  • Makes sense. I have used these tools to solve what I think are similar problems. Just not recently enough to provide a more precise answer. ;) – Will Feb 18 '20 at 21:23
  • 1
    FWIW, for a couple of memory leaks I hunted down a few years ago, the culprit each time was a detached event listener. In other words, DOM elements (with attached event listeners) were removed, but the listeners themselves weren't removed first and thus leaked. – Will Feb 18 '20 at 21:26

1 Answers1

1

I'm not sure if this is an answer to your question or not but ... in your details you wrote

I'd like to destroy the context and let the module and the textures, etc. be garbage collected.

Letting textures etc be garbage collected is the wrong way to clean up WebGL resources. See Are WebGL objects garbage collected?

If you know when WebAssembly is done you could track the resources from JavaScript by augmenting the context. Example

const allWebGL2ContextsResources = new Map();

HTMLCanvasElement.prototype.getContext = function(origFn) {
  return function(type, attribs) {
    const ctx = origFn.call(this, type, attribs);
    if (type === 'webgl2') {
      if (!allWebGL2ContextsResources.has(ctx)) {
        allWebGL2ContextsResources.set(ctx, new Set());
      }
    }
    return ctx;
  };
}(HTMLCanvasElement.prototype.getContext);

const types = ['Buffer', 'Texture', 'Renderbuffer', 'Framebuffer', 'Shader', 'Program', 'Sampler', 'TransformFeedback'];
for (const type of types) {
  const createName = `create${type}`;
  const deleteName = `delete${type}`;

  WebGL2RenderingContext.prototype[createType] = function(origFn) {
    return function(...args) {
      const obj = orignFn.call(this, ...args);
      allWebGL2ContextsResources.get(this).add(obj);
      return obj;
    };
  }(WebGL2RenderingContext.prototype[createType]);

  WebGL2RenderingContext.prototype[deleteType] = function(origFn) {
    return function(obj) {
      const obj = origFn.call(this, obj);
      allWebGL2ContextsResources(this).delete(obj);
    };
  }(WebGL2RenderingContext.prototype[deleteType]);
}

Given that, when you start the WebAssembly code a new WebGL2 context will get added to allWebGL2Contexts so you could diff with a copy before to find the context that was added. Or change the code to emit an event or call a callback or whatever you need to discover the context.

When you're done with the WebAssembly code you could then go through the resources and delete them. Example

for (const obj of allWebGL2ContextsResources.get(someContext).entries()) {
  for (const type of types) {
    const Type = `WebGL${type}`;
    if (obj instanceof window[Type]) {
      someContext[`delete${type}`](obj);
      continue;
    }
  }
}
allWebGL2ContextsResources.delete(someContext);

Or you could lose the context. See How do I clean up and unload a WebGL canvas context from GPU after use?

Assuming you're using emscripten then another option is that emscripten already tracks resources so you could modify the emscripten WebGL2 library to expose the context and the tracking or add some cleanup function to free everything that's tracked or lose the context.

gman
  • 100,619
  • 31
  • 269
  • 393