JavaScript
 Computer >> コンピューター >  >> プログラミング >> JavaScript

JavaScriptのメモリリークを根絶する方法

ガベージコレクション(GC)を備えた言語において、メモリリークの主な原因は「不要になったのに残ってしまう参照」です。メモリリークを正しく理解し防ぐために、まずメモリ解放の仕組みがどのように働いているのかを見ていきましょう。

マーク・アンド・スイープ(Mark-and-Sweep)アルゴリズム

このアルゴリズムでは、「オブジェクトがもう不要である」という概念を「オブジェクトが到達不可能である」という定義に置き換えます。アルゴリズムは「ルート(root)」と呼ばれる一連のオブジェクトを起点としており、JavaScriptではこのルートがグローバルオブジェクトに該当します。GCは定期的にこれらのルートから出発し、そこから参照されているすべてのオブジェクトを再帰的にたどります。こうしてルートから到達できるすべてのオブジェクトを特定し、到達できなかったオブジェクトだけを回収します。

メモリリークの主な種類

1. グローバル変数(宣言漏れ・意図しない宣言)

JavaScriptでは、let / var / const といった宣言キーワードを付け忘れると、変数が意図せずグローバルに宣言されてしまうことがあります。JSはスコープを外側へ向かって順にたどり、最終的にグローバルスコープまで到達します。そして、どのスコープにもその変数が見つからなければ、新しくグローバル変数を作成してしまうのです。

function test() {
    a = [1, 2, 3]
}
test()
// aは宣言キーワードなしで初期化されたため、グローバルスコープに存在することになります。
console.log(a)

出力

[1, 2, 3]

この動作はメモリリークの温床になります。変数が開発者の気づかないところでグローバルスコープに存在し続け、プログラムが終了するまで解放されないためです。この問題は、変数を宣言する際に必ず宣言キーワード(let や const など)を使用することで確実に防げます。

2. クロージャ

クロージャでは、外側の関数で宣言された変数が、ネストされた内側の関数から自動的にアクセス可能になります。その結果、内側の関数でその変数が実際には使われていない・参照されていない場合でも、変数はメモリ上に保持され続け、メモリリークが発生することがあります。

3. DOMから切り離されたノード(Detached DOM)/ DOM外参照

DOMは双方向にリンクされたツリー構造です。そのため、ツリー内の任意のノードへの参照が1つでも残っていると、そのツリー全体がガベージコレクションの対象になりません。「Detached DOM」や「DOM外参照」とは、すでにDOMから削除されたノードが、JavaScript経由で依然としてメモリ上に保持されている状態を指します。つまり、どこかに変数やオブジェクトへの参照が残っている限り、そのオブジェクトはDOMから取り除かれた後であってもガベージコレクションされません。DOMの一部を使い終わったら、必ずJavaScript側の参照も忘れずに削除しましょう。

4. イベントリスナー

addEventListener() メソッドは要素にイベントハンドラを登録するもので、1つの要素に対して複数のイベントハンドラを追加できます。しかし、DOM要素とそのイベントリスナーのライフサイクルが一致していない場合、不要になったリスナーがメモリ上に残り続け、メモリリークにつながる可能性があります。要素を削除する際には、removeEventListener() でリスナーを解除する習慣をつけることが重要です。

  1. JavaScript DOMとは?基本の仕組みと要素の取得方法をわかりやすく解説

    JavaScriptのDOM(Document Object Model:ドキュメントオブジェクトモデル)は、Webページ上のHTML要素を表現する仕組みです。DOMはインターフェースとして機能し、ページのコンテンツやスタイルを変更することで、Webページを自由に操作できるようにします。 DOMにアクセスするには、Webページ上で右クリックして「検証(Inspect)」を選択します。すると画面の右側または左側にパネルが表示され、現在閲覧しているページのHTML要素を確認できます。要素にマウスカーソルを合わせると、ページ上の該当部分がハイライトされるため、どの要素がページのどのセクションに対応

  2. JavaScriptでDOMを更新する方法!ボタンクリックで要素を動的に追加するサンプルコード

    JavaScriptでは、createElement()やcreateTextNode()、appendChild()といったメソッドを組み合わせることで、ページを再読み込みすることなく新しい要素を動的に生成し、DOM(Document Object Model)を更新できます。以下は、ボタンのクリックをきっかけに新しい見出し要素を追加するシンプルなサンプルコードです。 サンプルコード <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /&