How to detect if an object has been garbage collected in Javascript
WeakMap
At first, you may think that WeakMap will do it. WeakMap/WeakSet will hold onto things for you, but don't prevent an object from being garbage collected. The instant an object is GC'd, it is removed from the WeakMap or WeakSet.So, the obvious solution is to check if an object is still inside the WeakMap. If it is missing, it has been GC'd. This won't work.
The problem is that WeakMap and WeakSet are designed so that you cannot get at what's inside without already knowing it is there. In order to lookup an item, you need to already have that item. These collections don't even have a length method.
To check if an object is inside of a WeakMap, you must already have a reference to it, and therefore you are preventing it from being garbage collected.
So, what good are they? WeakMap is best used to link objects together. For example, if you have a bunch of <img> elements and you want to associate some data with them, you could simply do img.myextraproperty="blah". But your IDE may complain because the HTMLImageElement does not have this property. Instead, you can use WeakMap. If the extra property is a single value true then use a WeakSet.
The Real Solution
Some browsers, including Chrome but not Firefox, have the ability to check the amount of Javascript memory used. So the solution to test if an object is there, is to make it sufficiently large so that it has a noticeable impact on memory.In the code below, I use a WeakMap to associate a 1 gigabyte object with whatever you pass in. When the object is freed, and the garbage collector is run, you would expect at least 1 GB of memory to be freed as well. That is what the code checks for. The process takes at least 10 seconds, because it seems that Chrome only runs the garbage collector every 10 seconds.
/** Determines if an object is freed
@param obj is the object of interest
@param freeFn is a function that frees the object.
@returns a promise that resolves to {freed: boolean, memoryDiff:number}
@author Steve Hanov <steve.hanov@gmail.com>
*/
function isObjectFreed(obj, freeFn) {
return new Promise( (resolve) => {
if (!performance.memory) {
throw new Error("Browser not supported.");
}
// When obj is GC'd, the large array will also be GCd and the impact will
// be noticeable.
const allocSize = 1024*1024*1024;
const wm = new WeakMap([[obj, new Uint8Array(allocSize)]]);
// wait for memory counter to update
setTimeout( () => {
const before = performance.memory.usedJSHeapSize;
// Free the memory
freeFn();
// wait for GC to run, at least 10 seconds
setTimeout( () => {
const diff = before - performance.memory.usedJSHeapSize;
resolve({
freed: diff >= allocSize,
memoryDiff: diff - allocSize
});
}, 10000);
}, 100);
});
}
let foo = {bar:1};
isObjectFreed(foo, () => foo = null).then( (result) => {
document.write(`Object GCd:${result.freed}, ${result.memoryDiff} bytes freed`)
}, (error) => {
document.write(`Error: ${error.message}`)
})
How I use it
I use this method as part of my test suite for Zwibbler, my Javascript drawing app. It has a destroy() method that is supposed to remove all resources. But occasionally, I would have some event listener that was not removed, that would keep a reference to the entire application. So when using it inside something like React or Angular, where it can be repeatedly shown and hidden by the view framework, it is vitally important that resources be completely freed.Detecting C++ memory leaks
It's fairly simple to redefine malloc() and free() to your own functions, to track the file and line number of memory leaks.Draw waveforms and hear them
A while back I thought it would be interesting to be able to draw arbitrary waveforms and then listen to how they sound. I had an audio engine just laying around, so I whipped up a quick application to do that.
VP trees: A data structure for finding stuff fast
Let's say you have millions of pictures of faces tagged with names. Given a new photo, how do you find the name of person that the photo most resembles?
In the cases I mentioned, each record has hundreds or thousands of elements: the pixels in a photo, or patterns in a sound snippet, or web usage data. These records can be regarded as points in high dimensional space. When you look at a points in space, they tend to form clusters, and you can infer a lot by looking at ones nearby.
Using the Acer Aspire One as a web server
A netbook can be ideal for a home web server. They are cheap, and use less power
than a CFL light bulb.
Bending over: How to sell your software to large companies
For a micro-ISV, selling to businesses can be more lucrative than selling to consumers. Instead of making a few dollars per sale and hoping for thousands of sales, you sell to only a few customers, and charge much higher rates. But the rates are high for a reason. It takes more time and money to sell to businesses.
How a programmer reads your resume (comic)
People thought it was a comic, so I never corrected them.
