ActiveXObjectとスクリプトエンジン間の循環参照によるメモリリーク

IE6 SP2- の ActiveXObject 周りのメモリリーク問題はあまり知られていないような気がしたので、簡単にまとめておきます。

jQueryprototype.js では以下の方法で回避しています。

/**
 * メモリリークを回避する方法 (jQuery および prototype.js 方式)
 */ 

function empty () {
  // この関数は何も実行せず、何も参照しない位置に置く。何も参照しない故に循環参照しなくなる。
}

function get (url) {
  var xhr = new ActiveXObject('Msxml2.XMLHTTP.6.0');

  xhr.onreadystatechange = function () { // この関数は xhr を参照可能→循環参照している
    if (xhr.readyState === 4) {
      xhr.onreadystatechange = empty;    // xhr を参照不可能な empty を代入したので循環参照しなくなる
    }
  };

  xhr.open('GET', url, false);
  xhr.send(null);
}

get('/');

上記をもう少し簡単にしたコードがこちら。

/**
 * メモリリークを回避する方法 (new Function 方式)
 */ 

function get (url) {
  var xhr = new ActiveXObject('Msxml2.XMLHTTP.6.0');

  xhr.onreadystatechange = function () {     // この関数は xhr を参照可能→循環参照している
    if (xhr.readyState === 4) {
      xhr.onreadystatechange = new Function; // Function コンストラクタによって生成されたオブジェクトは xhr を参照不可能なので循環参照しなくなる
    }
  };

  xhr.open('GET', url, false);
  xhr.send(null);
}

get('/');

jQuery 方式では function empty の位置が重要で書き方を間違えると循環参照してしまいます。

new Function 方式では空の関数をその場で生成するので、置き場所に悩まなくて済みます。