JavaScriptのFinalizationRegistryは、オブジェクトのガベージコレクション後に実行されるコールバック関数を設定するための機能を提供するクラスです。この機能を使用することで、メモリリークを回避したり、解放後に後処理を行ったりすることができます。本チュートリアルでは、FinalizationRegistryの基本的な使い方や注意点について学び、実際のプログラムでの活用方法を紹介します。最新版のJavaScript環境を使っていることを前提に、具体的なコード例を交えて解説していきます。
__TOC__
JavaScriptのFinalizationRegistryは、オブジェクトがガベージコレクタ（GC）によって解放された際に、関数を呼び出す機能を提供するクラスです。JavaScriptでは、オブジェクトが不要になった場合、ガベージコレクタによって自動的に解放されます。しかし、この解放タイミングは保証されていません。
FinalizationRegistryは、この解放タイミングをより細かく制御できるようにするために、JavaScriptに導入されました。例えば、オブジェクトが解放されたときにデータベースからそのオブジェクトに関連する情報を削除するような場合に、FinalizationRegistryを使用することができます。
FinalizationRegistryは、オブジェクトのハンドルを保持し、オブジェクトがGCされた際に登録されたコールバック関数を呼び出すことができます。FinalizationRegistryに登録されたオブジェクトは、弱参照として保持されます。つまり、オブジェクトが他の参照を持っていない場合には、GCによって解放されます。
FinalizationRegistryは、JavaScriptのガベージコレクタと密接に関連しています。ガベージコレクタは、参照されていないオブジェクトを解放することでメモリを解放します。
FinalizationRegistryは、オブジェクトがGCされた際にコールバック関数を呼び出すため、オブジェクトの解放タイミングをコントロールすることができます。
FinalizationRegistryは、以下のような状況で役立ちます。
オブジェクトの解放時に必要な後処理を実行する必要がある場合。
大量のオブジェクトを管理する場合、メモリを効率的に管理するためにオブジェクトを解放する必要がある場合。
FinalizationRegistryを使用するには、まずFinalizationRegistryコンストラクタを使用して新しいFinalizationRegistryオブジェクトを作成します。次に、オブジェクトを登録するには、FinalizationRegistryのregister()メソッドを使用します。register()メソッドは、登録されたオブジェクトに対するコールバック関数を呼び出すためのハンドラー関数を登録します。そして、オブジェクトが解放されると、登録されたコールバック関数が自動的に呼び出されます。
以下は、FinalizationRegistryの簡単な例です。
const registry = new FinalizationRegistry((heldValue) => {
  console.log(`Object ${heldValue} has been released`);
});
let obj = { name: 'John' };
registry.register(obj, obj.name);
obj = null; // objをnullに設定して、オブジェクトを解放する
// コンソールには「Object John has been released」と表示されます。
この例では、FinalizationRegistryに登録されたコールバック関数が、オブジェクトが解放されたときに自動的に呼び出されています。
FinalizationRegistryを使用することで、JavaScriptアプリケーションのメモリ管理をより正確に制御することができます。しかし、FinalizationRegistryによる管理にはオーバーヘッドが発生するため、適切なタイミングで使用する必要があります。
JavaScriptの弱参照は、オブジェクトへの参照を保持しつつ、そのオブジェクトがGCの対象となった際に、強制的に解放することができる参照のことです。弱参照は、オブジェクトへの参照を保持することによって、オブジェクトがGCの対象にならないようにします。しかし、オブジェクトに他に参照がなくなった場合、弱参照はオブジェクトを自動的に解放することができます。
JavaScriptにおける弱参照は、WeakMap、WeakSet、FinalizationRegistryといった機能で利用されます。これらの機能は、オブジェクトの参照を保持しつつ、オブジェクトがGCされた際に自動的に解放することができます。例えば、WeakMapは、オブジェクトをキーとして保持し、キーに対する値を参照する際にオブジェクトへの弱参照を使用します。同様に、WeakSetは、オブジェクトの集合を保持する際にオブジェクトへの弱参照を使用します。
FinalizationRegistryは、弱参照を使用して、オブジェクトがGCされた際に自動的にコールバック関数を呼び出すことができます。FinalizationRegistryは、オブジェクトのハンドルを保持し、オブジェクトがGCされた際に登録されたコールバック関数を呼び出すことができます。FinalizationRegistryに登録されたオブジェクトは、弱参照として保持されます。つまり、オブジェクトが他の参照を持っていない場合には、GCによって解放されます。
弱参照は、JavaScriptのメモリ管理をより効率的に行うために非常に有用な機能です。例えば、大量のオブジェクトを管理する場合には、弱参照を使用して、オブジェクトを効率的に解放することができます。また、FinalizationRegistryを使用することで、オブジェクトが解放された際に必要な後処理を実行することができます。
FinalizationRegistry.prototype：FinalizationRegistryオブジェクトのプロトタイプを表します。
FinalizationRegistry.prototype.constructor：FinalizationRegistryオブジェクトのコンストラクタ関数を表します。
FinalizationRegistry.prototype[Symbol.toStringTag]：FinalizationRegistryオブジェクトのデフォルトの文字列表現を表します。
FinalizationRegistry.prototype.register(target, heldValue, unregisterToken)：FinalizationRegistryにオブジェクトを登録します。オブジェクトがガベージコレクションされたときに実行されるコールバック関数が、unregisterTokenというトークンとともに返されます。
FinalizationRegistry.prototype.unregister(unregisterToken)：registerメソッドで返されたトークンを使用して、FinalizationRegistryからオブジェクトを削除します。
FinalizationRegistry.prototype.cleanupSome(callback)：FinalizationRegistryの登録されたオブジェクトから、まだ生存しているもののうち、一部だけをクリーンアップします。callback関数は、クリーンアップされたオブジェクトの数を引数に取ります。
FinalizationRegistry.prototype.cleanupScheduled(): 前回の cleanupSome() メソッド呼び出し以降に登録されたオブジェクトから、まだ生存しているもののうち、一部だけをクリーンアップします。
これらのプロパティとメソッドを使用して、FinalizationRegistryオブジェクトを使用することができます。
以下はJavaScriptのFinalizationRegistryに関するチートシートです。各プロパティとメソッドについて、簡単な説明と例が含まれています。
// FinalizationRegistryのインスタンスを作成する
const registry = new FinalizationRegistry((heldValue) => {
  // heldValueがGCされるときに呼び出されるコールバック関数
  console.log(`heldValue ${heldValue} has been garbage collected`);
});
// FinalizationRegistryにオブジェクトを登録する
const obj = {name: 'John'};
registry.register(obj, 'some value');
// 'some value'がheldValueとしてコールバック関数に渡される
// FinalizationRegistryから登録を解除する
registry.unregister(obj);
// FinalizationRegistryに登録されているすべてのオブジェクトを強制的に解放する
registry.cleanupSome();
// FinalizationRegistryに登録されているすべてのオブジェクトを解放する
registry.cleanupNow();
注意: FinalizationRegistryはECMAScript 2021で導入されました。現在、すべてのブラウザでサポートされているわけではありません。詳細については、ブラウザのドキュメントを確認してください。
FinalizationRegistry: オブジェクトがGCされた際に、コールバック関数を呼び出すことができるクラスです。
register(target, heldValue): FinalizationRegistryにオブジェクトを登録します。登録するオブジェクトはtarget、heldValueは登録されたオブジェクトがGCされた際に、コールバック関数に渡される値です。
unregister(target): FinalizationRegistryからオブジェクトを登録解除します。
cleanupSome(): FinalizationRegistryに登録されている一部のオブジェクトを強制的に解放します。
cleanupNow(): FinalizationRegistryに登録されているすべてのオブジェクトを強制的に解放します。
heldValue: FinalizationRegistryに登録するオブジェクトがGCされた際に、コールバック関数に渡される値です。register()メソッドの第2引数として渡されます。
target: FinalizationRegistryに登録するオブジェクトです。register()メソッドの第1引数として渡されます。
コールバック関数: FinalizationRegistryに登録されたオブジェクトがGCされた際に、呼び出される関数です。FinalizationRegistryのコンストラクタで指定します。呼び出される際には、heldValueが引数として渡されます。
]]