Get to know MDN better
このページはコミュニティーの尽力で英語から翻訳されました。MDN Web Docs コミュニティーについてもっと知り、仲間になるにはこちらから。
C 言語のような低水準言語には、malloc() や free() のような低水準のメモリー管理プリミティブがあります。これに対して JavaScript では、オブジェクトを作成するときにメモリーを自動的に確保し、使用しなくなったらメモリーを自動的に解放します(ガベージコレクション)。この自動性が混乱の元になる可能性があります。メモリー管理について心配する必要がないという誤った印象を開発者に与える可能性があります。
プログラミング言語に関係なく、メモリーのライフサイクルはほぼいつも同じです。
2 に関してはすべての言語で明示的に行われます。1 と 3 は低水準の言語では明示的ですが、JavaScript のような高水準言語では、ほとんどの場合暗黙的に行われます。
割り当てでプログラマーを悩まさないために、JavaScript では値を宣言したときと同時にメモリーの割り当ても行われます。
一部の関数呼び出しでは、オブジェクトの割り当てが発生します。
いくつかのメソッドは、新しい値またはオブジェクトを割り当てます。
値を使用することは、基本的に割り当てられたメモリーに読み書きすることを意味します。これは変数やオブジェクトの値を読み書きすることや引数を関数に渡すことによって行われます。
メモリー管理の問題のほとんどは、この段階に来ます。ここで最も難しい作業は、「割り当てられたメモリーが、必要とされなくなるときを見出す」ことです。
プログラム内のどこで、そのようなメモリーの断片が不要になって解放する必要があるかを決定するには、開発者による判断が必要なことが多いです。
一部の高水準言語、例えば JavaScript は、ガベージコレクション (GC) として知られる自動メモリー管理の方式を利用しています。ガベージコレクターの目的は、メモリーの割り当てを監視し、割り当てられたメモリーのブロックができなくなったときに判断し、それを回収することです。特定のメモリーがまだ必要かどうかを判断する一般的な問題は決定不能であるため、この自動処理は近似的なものです。
上述の通り、あるメモリーが「必要なくなった」かどうかを自動的に知るという普遍的問題は、決定不能です。そのため、ガベージコレクションのこの普遍的問題に対する解決策には制限があります。この節では、ガベージコレクションの主なアルゴリズムとその限界を理解するために必要な概念を説明します。
ガベージコレクションアルゴリズムが依存している主な概念は、参照 (reference) の概念です。メモリー管理の文脈では、あるオブジェクトが別のオブジェクトに(明示的にであれ、暗黙的にであれ)アクセスできるとき、前者が後者を参照していると言います。例えば、JavaScript オブジェクトは自身のプロトタイプ(暗黙的な参照)とプロパティ値(明示的な参照)への参照を持ちます。
ここでは、「オブジェクト」の概念は通常の JavaScript オブジェクトよりも広い概念として用いられており、また、関数のスコープ(もしくは、グローバル字句スコープ)を含みます。
メモ: 現代の JavaScript エンジンで、ガベージコレクションに参照カウントを使用しているものはもうありません。
これは、最も素朴なガベージコレクションアルゴリズムです。このアルゴリズムは、「あるオブジェクトが必要なくなった」ことを、「あるオブジェクトがその他のオブジェクトから参照されていない」ことと定義します。あるオブジェクトは、それに対する参照がゼロの時にガベージコレクション可能であると見なされます。
循環参照があると、制限があります。以下の例では、互いに参照するプロパティを持つ 2 つのオブジェクトが作成され、循環を作り出しています。これらのオブジェクトは、関数の呼び出しが完全に終了すると、スコープ外に出ます。この点で、オブジェクトは不要となり、割り当てられたメモリーを回収する必要があります。しかし、参照カウントアルゴリズムは、2 つのオブジェクトがそれぞれ少なくとも 1 つの参照点を持っているため、それらを再生可能とは見なさず、結果的にどちらもガベージコレクションにマークされないことになります。参照するオブジェクトは、メモリーリークの一般的な発生させる原因です。
このアルゴリズムは、「あるオブジェクトが必要なくなった」ことを、「あるオブジェクトが到達不能である」ことと定義します。
このアルゴリズムは、root と呼ばれるオブジェクトの集合についての知識を前提としています(JavaScript では、root はグローバルオブジェクトです)。定期的に、ガベージコレクターは、これらの root から開始し、これらの root から参照されるすべてのオブジェクト、それから、これらの中から参照されるすべてのオブジェクトなどを見つけます。root から開始すると、ガベージコレクターは、すべての到達可能オブジェクトを見つけ、すべての到達不能なオブジェクトをガベージコレクトします。
「あるオブジェクトが参照を持たない」ということは、そのオブジェクトは到達不能であるということなので、このアルゴリズムは前述のものよりも優れています。循環で見たように、逆は正しくありません。
現在、すべての現代的なブラウザーでは、マークアンドスイープ式のガベージコレクターを持っています。過去数年間で JavaScript のガベージコレクション(世代別/インクリメンタル/並行/並列ガベージコレクション)の分野で行われたすべての改善は、このアルゴリズムの実装の改善であって、ガベージコレクションアルゴリズム自体に対する改善でも、「オブジェクトが必要とされなくなった」と扱う基準を変えるものでもありません。
この手法の直接的な好ましいことは、循環が問題にならなくなることです。上の最初の例では、関数呼び出しを返した後、2つのオブジェクトは、グローバルオブジェクトから到達可能などのリソースからも参照されなくなりました。その結果、これらはガベージコレクターによって到達できないことが分かり、割り当てられたメモリーが再利用されることになります。
しかし、ガベージコレクションを手動で制御することができないのは変わりません。いつ、どんなメモリーを解放するかを手動で決めることができれば便利な時があります。オブジェクトのメモリーを解放するためには、明示的に到達できないようにする必要があります。また、JavaScript ではプログラムによってガベージコレクションを発生させることはできませんし、エンジンがオプトインフラグで API を公開することはあっても、コア言語の中で発生することはないでしょう。
JavaScript エンジンは通常、メモリーモデルを公開するフラグを提供します。例えば、Node.js は、メモリーの問題を構成し、デバッグするために、基盤となるV8のメカニズムを公開する追加オプションやツールを提供しています。この設定は、ブラウザーでは利用できないかもしれませんし、ウェブページでは(HTTP ヘッダーなどを通じて)さらに利用できないかもしれません。
利用できるヒープメモリーの最大量は、フラグで増やすことができます。
また、フラグや Chrome デバッガーを用いて、メモリーの問題をデバッグするためにガベージコレクターを公開することができます。
JavaScript はガベージコレクター API を直接公開していませんが、この言語はガベージコレクションを間接的に監視するデータ構造をいくつか提供しており、メモリー使用量を管理するために使用することができます。
WeakMap と WeakSet には、データ構造がよく似た弱くない方の API、Map と Set があります。WeakMap はキーと値のペアの集合を、WeakSet は固有の値の集合を保持することができ、どちらも追加、削除、問い合わせの実行が可能である。
WeakMap と WeakSet は、weakly held 値の概念から取った名前です。x が y によって弱く保持されている場合、x の値には y を介してアクセスできますが、マークアンドスイープアルゴリズムでは、何か強く保持するものがなければ x に到達できるとは考えないということを意味しています。ここで議論するものを除くほとんどのデータ構造は、合格したオブジェクトをいつでも取り出せるように強く保持します。WeakMap と WeakSet のキーは、プログラム内でそのキーを参照しているものがない限り、ガベージコレクションすることができます(WeakMap オブジェクトの場合、値もガベージコレクションの対象となります)。これは、2 つの特徴によって確実に保持されます。
WeakMap や WeakSet の典型的な説明(上記のようなもの)では、キーが最初にガベージコレクションされ、値も同様にガベージコレクションのために解放されることが暗示されています。しかし、値をキーに参照する場合を考えてみましょう。
もし key が実際の参照として格納されると、循環参照が発生し、他に key を参照するものがない場合でも、キーと値の両方をガベージコレクションの対象外にしてしまいます。もし key がガベージコレクションされると、具体的なある瞬間に value.key が存在しないアドレスを指すことになり、これは不正な状態だからです。これを修正するために、WeakMap と WeakSet の項目は実際の参照ではなく、マークアンドスイープ機構を強化したエフェメロンです。Barros らは、このアルゴリズムの良い概要を提供しています(4 ページ目)。一段落を引用します。
エフェメロンは弱いペアを改良したもので、鍵も値も弱いとも強いとも分類できません。鍵の接続性は値の接続性を決定しますが、値の接続性は鍵の接続性には影響しません。 […] ガベージコレクションがエフェメロンに対応する場合、2 つのフェーズ(マークとスイープ)ではなく、3 つのフェーズで発生します。)
大まかなメンタルモデルとして、WeakMap は以下のような実装だと考えてください。
警告: これはポリフィルではなく、エンジンで実装されている方法(ガベージコレクション機構にフックしている)にも近いものです。
ご覧のように、MyWeakMapは実際にはキーの集合を保持することはありません。単に渡された各オブジェクトにメタデータを追加しているだけです。そのため、そのオブジェクトはマークアンドスイープによってガベージコレクションの対象になります。したがって、WeakMap内のキーを反復処理したり、WeakMapをクリアしたりすることはできません(これもすべてのキーの集合を把握している必要があるためです)。
これらの API の詳細については、キー付きコレクション のガイドを参照してください。
メモ: WeakRef と FinalizationRegistry は、ガベージコレクション機構に直接触れる機会を提供します。実行時の意味づけが完全に保証されていないため、可能な限り使用しないでください。
オブジェクトを値とする変数はすべて、そのオブジェクトを参照しています。しかし、このような参照は 強い ものであり、その存在によってガベージコレクタがそのオブジェクトを収集対象としてマークすることができなくなります。WeakRef は、オブジェクトへの弱い参照で、オブジェクトをガベージコレクションすることができ、かつオブジェクトが生きている間にそのコンテンツを読むことができるようにします。
WeakRef の用途として、文字列の URL を大きなオブジェクトに割り当てるキャッシュシステムがあります。そのために WeakMap を使用することはできません。なぜなら、WeakMap オブジェクトは キー を弱く保持しますが、値 は弱く保持しないからです。キーにアクセスすれば、常に決定論的に値が取得されます(キーにアクセスしていることは、それがまだ生きていることを意味するからです)。ここで、キーに対して undefined を取得しても(対応する値が使えなくなった場合)、再計算すればよいので問題ありませんが、到達できないオブジェクトがキャッシュに残ってしまうのは困ります。この場合、通常の Map を使用しますが、各値は実際のオブジェクトの値ではなく、オブジェクトの WeakRef となります。
FinalizationRegistry は、ガベージコレクションを監視するさらに強力なメカニズムを提供します。これは、オブジェクトを登録し、それらがガベージコレクションされたときに通知されるようにするものです。例えば、上で説明したキャッシュシステムの例では、Blob 自体はガベージコレクションの対象になったとしても、それを保持しているWeakRefオブジェクトはそうではないため、時間が経つとMapに無駄なエントリがたくさん溜まってしまう可能性があります。FinalizationRegistryを使用することで、このような用途のクリーンアップを行うことができます。
パフォーマンスとセキュリティの関係で、コールバックがいつ呼び出されるか、あるいはすべて呼び出されるかどうかは保証されていません。コールバックはクリーンアップにのみ使用すべきであり、しかも重要でないクリーンアップにのみ使用すべきです。他にも、try...finally で常に実行される finally ブロックで実行するなど、より決定的にリソースを管理する方法があります。WeakRef と FinalizationRegistry は、長時間実行するプログラムのメモリー使用量を最適化するためだけに存在します。
WeakRef および FinalizationRegistry の API について詳しくは、それぞれのリファレンスページを参照してください。
This page was last modified on 2026年3月21日 by MDN contributors.
Your blueprint for a better internet.
Visit Mozilla Corporation’s not-for-profit parent, the Mozilla Foundation.
Portions of this content are ©1998–2026 by individual mozilla.org contributors. Content available under a Creative Commons license.