nsITimer anti-pattern

I’ve filed bug 640629 to address an intermittent source of orange: incorrect nsITimer creation. I first ran across it while working on making httpd.js collect garbage more frequently, a task which quickly turned into orange whack-a-mole as more and more problematic test constructs popped out of the nether. Mounir Lamouri (volkmar) recently fixed another instance of the nsITimer problem, so I thought I’d address it in public and do some education.

When you see a construct like this, you should be wary:

function doSomething() {
  var timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
  timer.initWithCallback(callback, delay, timer.TYPE_ONE_SHOT);

There’s a common misconception that timers retain an extra reference that is released after they fire. This is false. If a timer is created and stored in a locally-scoped variable and the scope is exited, the timer is at risk of being garbage-collected before the timer fires. To combat this, store a reference to the timer elsewhere – a member of an object that outlives the current scope, a global variable, it doesn’t matter. Do your part – save a timer’s life today.

4 Responses to “nsITimer anti-pattern”

  1. Yeah, that’s the one that almost everybody gets wrong. I don’t think that anybody expects the timer to be garbage-collected and the warning on MDC is easy to overlook.

  2. I think if you use the init() method, the observer reference holds the timer for you and this problem doesn’t occur.

  3. Hi, is the bug in the first reference to ‘timer’ (timer.initWithCallback) or the second one (timer.TYPE_ONE_SHOT) ? Thanks

  4. The bug is in the expectation that the timer will always fire after leaving the scope of doSomething, since the timer object could be GCed at any time.

Leave a Reply