jQueryを使って要素を追加したり消したりするときに、特に意識せず書いていたらメモリーリーク起こしちゃってたのでメモ。

たとえば以下のようなコード。

addを押したらspan要素が増えていって、next、prevで選択中の要素(赤色)が変わっていく。"remove unselected"で選択中の要素以外の要素を消す。

これで以下のような操作をするとメモリーリークする(DOMから削除された不要な要素がメモリに残り続ける)。

  1. add を何回か押して要素を足す
  2. next を何回か押して選択要素を変える
  3. remove unselected を押して選択要素以外を削除

原因は、jQueryでnext()やprev()などを使って(あるいは他のメソッドでもだが)要素を次々と移っていったときに、current.prevObject にその前の要素を保持しているせいである。今回はjQueryオブジェクトをプログラムの実行中ずっと保持し続けているので、そこからprevObjectを辿っていくことで消したはずの要素にもアクセスできるようになってしまっている。

以下は実際にprevObjectの中身を出力して、消したはずの要素がメモリに残っているのを確認できるようにしたもの。

"show hisotry"を押すと、それまでの移動履歴が表示され、削除された要素も残っていることが分かる。
(demoは実際に上記のメモリーリークを起こすパターンを再現するようにしたもの)

対策としては、そもそもjQueryオブジェクトを保持しておくのをやめればよい。たとえば代わりに素のDOMオブジェクトで保持したり、もしくは選択中であることを示すclassを付けるなどして代替するのがおそらく望ましい。

一応、以下のような方法で jQuery の prevObject をリセットすることもできる:

delete element.prevObject;
もしくは
element = $(element);