ファイナライザー

ウィキペディアから、無料の百科事典
ナビゲーションにジャンプ 検索にジャンプ

コンピュータサイエンスではファイナライザーまたはファイナライズメソッドは、ファイナライズを実行する特別なメソッドであり、通常は何らかの形式のクリーンアップです。ファイナライザーは、オブジェクトの割り当てが解除される前のオブジェクトの破棄中に実行され割り当て続いオブジェクトの作成中に実行されるイニシャライザーを補完しますファイナライザーは、適切な使用が困難で複雑であるため、一部の人には強く推奨されていません。代わりに、主にディスポーズパターン[1]の代替案が提案されています。ファイナライザーの問題を参照してください。

「ファイナライザー」という用語は、主にガベージコレクションを使用するオブジェクト指向および関数型言語で使用されます。その原型はSmalltalkです。これは、決定論的なオブジェクトの有効期間を持つ言語(通常はC ++)でファイナライズを要求されるメソッドである「デストラクタ」とは対照的です[2] [3]これらは一般的に排他的です。言語には、ファイナライザー(自動的にガベージコレクションされる場合)またはデストラクタ(手動でメモリ管理される場合)のいずれかがありますが、まれに、C ++/CLIDのように言語に両方がある場合があります。参照カウントの場合(ガベージコレクションをトレースする代わりに)、用語は異なります。技術的な使用法では、「ファイナライザ」はデストラクタを指すために使用されることもあります。デストラクタはファイナライズも実行し、いくつかの微妙な区別が描かれているためです。用語を参照してください。「最終」という用語は、継承できないクラスを示すためにも使用されますこれは無関係です。

用語

「ファイナライザー」と「ファイナライズ」と「デストラクタ」と「デストラクタ」の用語は、作成者によって異なり、不明確な場合があります。

一般的な使用法では、デストラクタはオブジェクト破壊で決定論的に呼び出されるメソッドであり、原型はC++デストラクタです。一方、ファイナライザーはガベージコレクターによって非決定論的に呼び出され、原型はJavafinalizeメソッドです。

参照カウントを介してガベージコレクションを実装する言語の場合、用語は異なります。Objective-CやPerlなどの一部の言語では「デストラクタ」を使用し、Pythonなどの他の言語では「ファイナライザー」を使用します(仕様によれば、Pythonはガベージコレクションですが、リファレンスバージョン2.0以降のCPythonの実装では、参照カウントとガベージコレクションの組み合わせを使用しています)。これは、参照カウントが半決定論的なオブジェクトの存続期間をもたらすという事実を反映しています。サイクルの一部ではないオブジェクトの場合、参照カウントがゼロになるとオブジェクトは決定論的に破棄されますが、サイクルの一部であるオブジェクトは非決定論的に破棄されます、ガベージコレクションの別の形式の一部として。

特定の狭い技術的使用法では、「コンストラクタ」と「デストラクタ」は言語レベルの用語であり、「クラスで定義されたメソッド」を意味します。一方、「初期化子」と「ファイナライザー」は実装レベルの用語であり、「オブジェクトの作成中に呼び出されるメソッド」または破壊"。したがって、たとえば、C#はガベージコレクションされますが、C#言語の元の仕様では「デストラクタ」と呼ばれていましたが、共通言語インフラストラクチャ(CLI)の仕様と、そのランタイム環境の実装は共通言語ランタイム(CLR)です。 )、「ファイナライザー」と呼ばれます。これは、C#言語委員会のメモに反映されています。このメモには次のように書かれています。「C#コンパイラはデストラクタを...にコンパイルします。この用語は紛らわしいため、C#仕様の最近のバージョンでは、言語レベルのメソッドを「ファイナライザー」と呼んでいます。[6]

この用語を区別しない別の言語はDです。Dクラスはガベージコレクションされますが、それらのクリーンアップ機能はデストラクタと呼ばれます。[7]

を使用

ファイナライズは、主にクリーンアップ、メモリまたはその他のリソースの解放に使用されます。手動のメモリ管理を介して割り当てられたメモリの割り当てを解除します。参照カウントが使用されている場合に参照をクリアする(参照カウントをデクリメントする)。特にリソース獲得は初期化であり、リソースを解放する(RAII)イディオム; またはオブジェクトの登録を解除します。ファイナライズの量は、手動のメモリ管理、参照カウント、および決定論的なオブジェクトの有効期間を備えたC ++での広範なファイナライズから、言語間で大幅に異なります。多くの場合、Javaでのファイナライズはありません。これは、非決定論的なオブジェクトの有効期間があり、トレースガベージコレクターを使用して実装されることがよくあります。明示的な(ユーザー指定の)ファイナライズがほとんどまたはまったくない可能性もありますが、コンパイラー、インタープリター、またはランタイムによって実行される重要な暗黙のファイナライズがあります。これは、PythonのCPythonリファレンス実装のように自動参照カウントの場合、またはAppleのObjective-Cの実装の自動参照カウントの場合に一般的です。、どちらもファイナライズ中に自動的に参照を解除します。ファイナライザには任意のコードを含めることができます。特に複雑な使用法は、オブジェクトをオブジェクトプールに自動的に返すことです。

ファイナライズ中のメモリの割り当て解除は、手動メモリ管理が標準であるC ++のような言語で一般的ですが、メモリが管理対象ヒープの外部(言語の外部)に割り当てられている場合、管理対象言語でも発生します。Javaでは、これはJava Native Interface(JNI)およびNew I / O(NIO)のByteBufferオブジェクトで発生します。この後者は、ガベージコレクターがこれらの外部リソースを追跡できないために問題を引き起こす可能性があるため、十分に積極的に収集されず、管理されていないメモリを使い果たすためにメモリ不足エラーを引き起こす可能性があります。これは、ネイティブを処理することで回避できます。以下で説明するように 、リソースとしてメモリを使用し、disposeパターンを使用します。

ファイナライザは一般に、デストラクタよりも必要性がはるかに低く、使用もはるかに少なくなっています。ガベージコレクションはメモリ管理を自動化するため、必要性ははるかに低く、一般的に決定論的に実行されないため、使用量ははるかに少なくなります。タイムリーに呼び出されないか、まったく呼び出されない可能性があり、実行環境を予測できません。したがって、決定論的な方法で実行する必要があるクリーンアップは、代わりに他の方法で実行する必要があります。ほとんどの場合、disposeパターンを使用して手動で実行する必要があります。特に、JavaとPythonはどちらも、ファイナライザーが呼び出されることを保証していないため、クリーンアップに依存することはできません。

プログラマーが実行を制御できないため、通常、最も些細な操作以外のファイナライザーを避けることをお勧めします。特に、デストラクタで頻繁に実行される操作は、通常、ファイナライザに適していません。一般的なアンチパターンは、ファイナライザをデストラクタであるかのように記述することです。これは、ファイナライザとデストラクタの違いにより、不要であり、効果がありません。これは、 C ++プログラマーの間で特に一般的です。これは、リソース取得が初期化(RAII)イディオム に従って、デストラクタが慣用的なC++で頻繁に使用されるためです。

構文

ファイナライザーを使用するプログラミング言語には、C ++ / CLIC#CleanGoJava、およびPythonが含まれます。構文は言語によって大きく異なります。

Javaでは、ファイナライザーは、メソッドと呼ばれるメソッドfinalizeであり、メソッドをオーバーライドしますObject.finalize[8]

Pythonでは、ファイナライザーは。と呼ばれるメソッド__del__です。

Perlでは、ファイナライザーは。と呼ばれるメソッドDESTROYです。

~C#では、ファイナライザー(以前のバージョンの標準では「デストラクタ」と呼ばれていました)は、次のように名前が接頭辞付きのクラス名であるメソッドです。これはC ++デストラクタ~Fooと同じ構文であり、これらのメソッドは元々「デストラクタ」と呼ばれていました。 "、C ++と同様に、動作は異なりますが、混乱が生じたため、名前が「ファイナライザー」に変更されました。[6]

デストラクタとファイナライザの両方を持つC++/ CLIでは、デストラクタは(C#のように)プレフィックスが付いたクラス名であるメソッドであり、ファイナライザは名前がプレフィックスが付いたクラス名であるメソッド~です。で~Foo!!Foo

runtime.SetFinalizerGoでは、ファイナライザーは、標準ライブラリの関数を呼び出すことにより、単一のポインターに適用されます。[9]

実装

ファイナライザーは、オブジェクトがガベージコレクションされたとき、つまりオブジェクトがガベージ(到達不能)になった後、メモリの割り当てが解除される前に呼び出されます。ファイナライズは、ガベージコレクターの裁量で非決定論的に発生し、発生しない可能性があります。これは、オブジェクトが使用されなくなるとすぐに決定論的に呼び出され、制御されていないプログラム終了の場合を除いて常に呼び出されるデストラクタとは対照的です。ファイナライザーは、オブジェクト固有の操作を行う必要があるため、 ほとんどの場合インスタンスメソッドです。

ガベージコレクターは、オブジェクトの復活の可能性も考慮する必要があります。最も一般的には、これは最初にファイナライザーを実行し、次にオブジェクトが復活したかどうかを確認し、復活した場合はその破壊を中止することによって行われます。この追加のチェックは潜在的にコストがかかります。単一のオブジェクトにファイナライザーがある場合、単純な実装ですべてのガベージが再チェックされるため、ガベージコレクションの速度が低下し複雑になります。このため、ファイナライザーのあるオブジェクトは、ファイナライザーのないオブジェクトよりも収集頻度が低く(特定のサイクルのみ)、リソースリークなどの迅速なファイナライズに依存することによって引き起こされる問題を悪化させる可能性があります。

オブジェクトが復活した場合、次に破棄されたときにファイナライザーが再度呼び出されるかどうかという問題があります。デストラクタとは異なり、ファイナライザーは複数回呼び出される可能性があります。復活したオブジェクトに対してファイナライザーが呼び出された場合、オブジェクトは繰り返し復活し、破壊されない可能性があります。これは、Python 3.4より前のPythonのCPython実装、およびC#などのCLR言語で発生します。これを回避するために、Java、Objective-C(少なくとも最近のApple実装では)、Python 3.4のPythonを含む多くの言語では、オブジェクトは最大で1回ファイナライズされます。これには、オブジェクトがまだファイナライズされているかどうかを追跡する必要があります。

その他の場合、特にC#などのCLR言語では、ファイナライズはオブジェクト自体とは別に追跡され、オブジェクトはファイナライズのために繰り返し登録または登録解除できます。

問題

ファイナライザーはかなりの数の問題を引き起こす可能性があるため、多くの当局によって強く推奨されていません。[10] [11]これらの問題は次のとおりです。[10]

  • ファイナライザーはタイムリーに呼び出されないか、まったく呼び出されない可能性があるため、状態を維持したり、不足しているリソースを解放したり、その他の重要なことを実行したりすることはできません。
  • ファイナライザーはオブジェクトの復活を引き起こす可能性があります。これはプログラミングエラーであることが多く、その可能性が非常に高くなり、ガベージコレクションが複雑になります。
  • ファイナライザーは、ガベージコレクションに基づいて実行されます。これは通常、管理されたメモリの負荷に基づいています。他のリソースが不足している場合は実行されないため、他の不足しているリソースの管理には適していません。
  • ファイナライザーは指定された順序で実行されず、クラスの不変条件に依存できません(既にファイナライズされている他のオブジェクトを参照している可能性があるため)。
  • ファイナライザーが遅いと、他のファイナライザーが遅れる場合があります。
  • ファイナライザーは不特定の環境で実行され、無視されるか、制御されていないプログラムの終了を引き起こす可能性があるため、ファイナライザー内の例外は通常処理できません。
  • ファイナライザーは、プログラムの不変条件に違反して、ライブオブジェクトを参照し、誤ってファイナライズする可能性があります。
  • ファイナライザーは、それ以外の場合はシーケンシャル(シングルスレッド)プログラムでも、ファイナライズが同時に(具体的には、1つ以上の別々のスレッドで)行われる可能性があるため、同期の問題を引き起こす可能性があります。[12]
  • ファイナライザーは、ロックなどの同期メカニズムが使用されている場合、指定された順序で実行されておらず、同時に実行されている可能性があるため、デッドロックを引き起こす可能性があります。
  • プログラムの終了時に実行されるファイナライザーは、通常のランタイム環境に依存できないため、誤った仮定が原因で失敗する可能性があります。このため、ファイナライザーは終了時に実行されないことがよくあります。

さらに、ファイナライザーは、プログラミングエラーまたは予期しない到達可能性のために、オブジェクトがガベージであると予想される時間を超えて到達可能であるために実行に失敗する可能性があります。たとえば、Pythonが例外をキャッチした場合(または例外がインタラクティブモードでキャッチされなかった場合)、Pythonは例外が発生したスタックフレームへの参照を保持し、そのスタックフレームから参照されたオブジェクトを存続させます。

スーパークラスのファイナライザーは、サブクラスのガベージコレクションを遅くする可能性もあります。これは、ファイナライザーがサブクラスのフィールドを参照する可能性があるため、ファイナライザーが実行されると、次のサイクルまでフィールドをガベージコレクションできないためです。[10]これは、継承よりも合成を使用することで回避できます

リソース管理

一般的なアンチパターンは、ファイナライザーを使用してリソースを解放することです。これは、C++のResourceAcquisition Is Initialization(RAII)イディオムと同様です。初期化子(コンストラクター)でリソースを取得し、ファイナライザー(デストラクタ)で解放します。これは、いくつかの理由で機能しません。最も基本的に、ファイナライザーは呼び出されない可能性があり、呼び出されたとしても、タイムリーに呼び出されない可能性があります。したがって、ファイナライザーを使用してリソースを解放すると、通常、リソースリークが発生します。さらに、ファイナライザーは所定の順序で呼び出されませんが、リソースは特定の順序で解放される必要があり、多くの場合、リソースが取得されたのとは逆の順序で解放されます。また、ファイナライザーはガベージコレクターの裁量で呼び出されるため、リソースのプレッシャーに関係なく、マネージドメモリのプレッシャー(使用可能なマネージドメモリがほとんどない場合)でのみ呼び出されることがよくあります。使用可能な管理対象メモリーの数が少ないと、ガベージコレクションが発生しない可能性があるため、これらのリソースを再利用できません。

したがって、自動リソース管理にファイナライザーを使用する代わりに、ガベージコレクションされた言語では、通常はdisposeパターンを使用してリソースを手動で管理する必要があります。この場合、リソースは、オブジェクトのインスタンス化で明示的に呼び出される初期化子で引き続き取得できますが、disposeメソッドで解放されます。usingdisposeメソッドは、明示的に呼び出すことも、C# 、Javaのtry-with-resources、Pythonなどの言語構造によって暗黙的に呼び出すこともできますwith

ただし、場合によっては、リソースの解放にディスポーズパターンとファイナライザーの両方が使用されます。これは主にC#などのCLR言語で見られ、ファイナライズは廃棄のバックアップとして使用されます。リソースが取得されると、取得するオブジェクトはファイナライズのためにキューに入れられ、リソースがオブジェクトの破棄時に解放されます。手作業で廃棄してリリース。

決定論的および非決定論的オブジェクトの存続期間

決定論的なオブジェクトの有効期間を持つ言語、特にC ++では、リソースの所有期間をオブジェクトの有効期間に結び付け、初期化中にリソースを取得し、ファイナライズ中にリソースを解放することによって、リソース管理が頻繁に行われます。これは、Resource Acquisition Is Initialization(RAII)として知られています。これにより、リソースの所有がクラス不変になり、オブジェクトが破棄されたときにリソースがすぐに解放されます。

ただし、オブジェクトの有効期間が決定論的でない言語(C#、Java、Pythonなどのガベージコレクションを含むすべての主要言語を含む)では、ファイナライズがタイムリーでないか、まったく行われない可能性があるため、これは機能しません。長期間またはまったくリリースされない可能性があり、リソースリークが発生する可能性があります。これらの言語では、リソースは通常、disposeパターンを介して手動で管理されます。リソースは初期化中に取得される場合がありますが、メソッドを呼び出すことによって解放されdisposeます。それでも、これらの言語でリソースを解放するためにファイナライズを使用することは一般的なアンチパターンであり、呼び出しを忘れるとdisposeリソースリークが発生します。

場合によっては、明示的なdisposeメソッドを使用して両方の手法を組み合わせるだけでなく、バ​​ックアップとしてファイナライズ中にまだ保持されているリソースを解放することもあります。これはC#で一般的に見られ、リソースが取得されるたびにファイナライズ用のオブジェクトを登録し、リソースが解放されるたびにファイナライズを抑制することによって実装されます。

オブジェクトの復活

ユーザー指定のファイナライザーが許可されている場合、ファイナライザーは任意のコードを実行でき、ライブオブジェクトから破棄されているオブジェクトへの参照を作成する可能性があるため、ファイナライズによってオブジェクトが復活する可能性があります。ガベージコレクションのない言語の場合、これは重大なバグであり、参照がぶら下がったり、メモリ安全性違反が発生したりします。ガベージコレクションのある言語の場合、これはガベージコレクターによって防止されます。最も一般的には、ガベージコレクションに別のステップを追加することで(ユーザー指定のファイナライザーをすべて実行した後、復活を確認します)、ガベージコレクションが複雑になり速度が低下します。

さらに、オブジェクトの復活とは、オブジェクトが破壊されない可能性があることを意味し、病理学的な場合、オブジェクトはファイナライズ中に常にそれ自体を復活させることができ、それ自体を破壊できなくなります。これを防ぐために、JavaやPython(Python 3.4以降)などの一部の言語は、オブジェクトを1回だけファイナライズし、復活したオブジェクトをファイナライズしません。[要出典]具体的には、これは、オブジェクトがオブジェクトごとにファイナライズされているかどうかを追跡することによって行われます。Objective-Cは、同様の理由で ファイナライズ(少なくとも最近の[いつ? ] Appleバージョン[説明が必要] )も追跡し、復活をバグとして扱います。

.NET Framework、特にC#とVisual Basic .NETでは、オブジェクトではなく「キュー」によってファイナライズが追跡される別のアプローチが使用されます。この場合、ユーザー指定のファイナライザーが提供されている場合、デフォルトでは、オブジェクトは1回だけファイナライズされます(作成時にファイナライズのためにキューに入れられ、ファイナライズされるとデキューされます)が、これはGCモジュールを呼び出すことで変更できます。GC.SuppressFinalizeファイナライズは、オブジェクトをデキューするを呼び出すことによって防ぐことができます。または、オブジェクトをエンキューするを呼び出すことによって再アクティブ化することができGC.ReRegisterForFinalizeます。これらは、廃棄パターンの補足としてリソース管理のファイナライズを使用する場合、またはオブジェクトプールを実装する場合に特に使用されます。

初期化と対比

ファイナライズは、形式的には初期化を補完します。初期化はライフタイムの開始時に発生し、ファイナライズは終了時に発生しますが、実際には大きく異なります。変数とオブジェクトの両方は、主に値を割り当てるために初期化されますが、通常はオブジェクトのみがファイナライズされ、一般に値をクリアする必要はありません。メモリの割り当てを解除して、オペレーティングシステムで再利用するだけです。

初期化は、初期値を割り当てる以外に、主にリソースを取得したり、オブジェクトを何らかのサービス(イベントハンドラーなど)に登録したりするために使用されます。)。これらのアクションには対称的なリリースまたは登録解除アクションがあり、これらはRAIIで実行されるファイナライザーで対称的に処理できます。ただし、多くの言語、特にガベージコレクションを使用する言語では、オブジェクトの有効期間は非対称です。オブジェクトの作成はコード内の明示的なポイントで決定論的に行われますが、オブジェクトの破棄は、特定されていない環境では、ガベージコレクターの裁量で非決定論的に行われます。この非対称性は、ファイナライズがタイムリーに、指定された順序で、または指定された環境で行われないため、初期化の補完として効果的に使用できないことを意味します。オブジェクトを明示的なポイントに配置することによって対称性が部分的に復元されますが、この場合、廃棄と破棄は同じポイントでは発生せず、オブジェクトは「クラスの不変条件と複雑な使用。

変数は通常、ライフタイムの開始時に初期化されますが、ライフタイムの終了時にファイナライズされません。ただし、変数の値にオブジェクトがある場合、オブジェクトはファイナライズされる可能性があります。場合によっては、変数もファイナライズされます。GCC拡張機能を使用すると、変数をファイナライズできます。

finallyとの接続

ネーミングに反映されているように、「ファイナライズ」とfinally構成はどちらも同様の目的を果たします。つまり、他の何かが終了した後に、最終的なアクションを実行し、通常はクリーンアップします。それらは発生するタイミングが異なります–finallyプログラムの実行が関連するtry句の本体を離れるときに句が実行されます–これはスタックの巻き戻し中に発生するため、保留中のfinally句のスタックが順番にあります–オブジェクトが破棄されると、ファイナライズが発生します。これはメモリ管理方法に応じて発生し、一般に、特定の順序で発生する必要のない、ファイナライズを待機しているオブジェクトのセット(多くの場合ヒープ上)があります。

ただし、これらが一致する場合もあります。C ++では、オブジェクトの破棄は決定論的であり、finally句の動作は、オブジェクトを値として持つローカル変数を持つことによって生成できます。そのスコープは、try句の本体に対応するブロックです。オブジェクトは、次の場合にファイナライズ(破棄)されます。実行は、finallyがあった場合とまったく同じように、このスコープを終了します。このため、C ++には構成がありません。違いは、ファイナライズが、finallyの呼び出しサイトではなく、デストラクタメソッドとしてクラス定義で定義されることです。finally

逆に、Pythonジェネレーターのように、コルーチンfinally内の節の場合、コルーチンは決して終了しない可能性があります。したがって、通常の実行では、節は実行されません。コルーチンのインスタンスをオブジェクトとして解釈する場合、その句はオブジェクトのファイナライザーと見なすことができるため、インスタンスがガベージコレクションされたときに実行できます。Pythonの用語では、コルーチンの定義はジェネレーター関数であり、そのインスタンスはジェネレーターイテレーターであるため、ジェネレーター関数の句は、この関数からインスタンス化されたジェネレーターイテレーターのファイナライザーになります。 finallyfinallyfinally

歴史

オブジェクト破壊の別個のステップとしてのファイナライズの概念は、 Martin&Odell(1992)のオブジェクト構築における初期化の以前の区別との類推によりMontgomery(1994)[13]にまでさかのぼります[14]この時点より前の文献では、このプロセスに「破壊」が使用されており、ファイナライズと割り当て解除は区別されていません。C++やPerlなど、この時代のプログラミング言語では「破壊」という用語が使用されています。「ファイナライズ」および「ファイナライズ」という用語は、影響力のある本Design Patterns(1994)でも使用されています。[a] [15] 1995年のJavaの導入にはfinalizeこの用語を普及させてガベージコレクションに関連付けたメソッド、およびこの時点からの言語は、一般にこの区別を行い、特にガベージコレクションのコンテキストで「ファイナライズ」という用語を使用します。


も参照してください

メモ

  1. ^ 1994年に発行され、1995年の著作権があります。

参照

  1. ^ Jagger、Perry&Sestoft 2007、p。 542、「C ++では、デストラクタは確定的に呼び出されますが、C#では、ファイナライザは呼び出されません。C#から確定的な動作を取得するには、次を使用する必要があります。Dispose.
  2. ^ ベーム、ハンス-J。(2002)。デストラクタ、ファイナライザ、および同期POPL。
  3. ^ Jagger、Perry&Sestoft 2007、p。 542 C++デストラクタとC#ファイナライザーC ++デストラクタは、既知の時点で、既知の順序で、既知のスレッドから実行されるという意味で決定されます。したがって、これらは、未知の時点、未知の順序、未知のスレッド、およびガベージコレクターの裁量で実行されるC#ファイナライザーとは意味的に非常に異なります。
  4. ^ 完全に:「インスタンスが再利用されたときに実行されるメンバーに「デストラクタ」という用語を使用します。クラスにはデストラクタを含めることができますが、構造体にはできません。C++とは異なり、デストラクタを明示的に呼び出すことはできません。 -決定論的–オブジェクトへのすべての参照が解放された後のある時点で実行される場合を除いて、デストラクタがいつ実行されるかを確実に知ることはできません。継承チェーン内のデストラクタは、子孫から順に呼び出されます。子孫。派生クラスがベースデストラクタを明示的に呼び出す必要はありません(方法もありません)。C#コンパイラはデストラクタを適切なCLR表現にコンパイルします。このバージョンでは、おそらくメタデータで区別されるインスタンスファイナライザを意味します。CLRは将来的に静的ファイナライザーを提供します。静的ファイナライザーを使用したC#に対する障壁は見られません。」、1999年5月12日。
  5. ^ デストラクタとファイナライザの違いは何ですか?、Eric Lippert、 Eric Lippertのブログ:コーディングにおける素晴らしい冒険、 2010年1月21日
  6. ^ a b Jagger、Perry&Sestoft 2007、p。 542、「この標準の以前のバージョンでは、現在「ファイナライザー」と呼ばれているものは「デストラクタ」と呼ばれていました。経験によれば、「デストラクタ」という用語は混乱を引き起こし、特に知っているプログラマーにとっては誤った期待をもたらすことがよくありました。 C++。C++では、デストラクタは確定的な方法で呼び出されますが、C#では、ファイナライザは呼び出されません。C#から確定的な動作を取得するには、Dispose.
  7. ^ クラスデストラクタDのクラスデストラクタ
  8. ^ java.lang、クラスオブジェクト:ファイナライズ
  9. ^ 「ランタイムパッケージ-ランタイム-PKG.go.dev」
  10. ^ a b c " MET12-J.ファイナライザーを使用しないでください"、Dhruv Mohindra、CERT Oracle Secure Coding Standard for Java05。メソッド(MET)
  11. ^ object .__ del __(self) Python言語リファレンス 3。データモデル:「...__del__()メソッドは、外部不変条件を維持するために必要な最小限のことを実行する必要があります。」
  12. ^ ハンス-J。Boehm、ファイナライズ、スレッド、およびJava™テクノロジーベースのメモリモデル、JavaOne Conference、2005年。
  13. ^ Montgomery 1994、p。 120、「オブジェクトのインスタンス化と同様に、オブジェクトの終了の設計は、クラスごとに2つの操作(finalize操作とterminate操作)を実装することでメリットが得られます。finalize操作、他のオブジェクトとの関連付けを解除し、データ構造の整合性を確保します。」
  14. ^ Montgomery 1994、p。 119、「MartinとOdellが提案したように、クラスのインスタンス化を作成および初期化操作として実装することを検討してください。最初は新しいオブジェクトにストレージを割り当て、2番目は仕様と制約に準拠するようにオブジェクトを構築します。」
  15. ^ "すべての新しいクラスには、固定の実装オーバーヘッド(初期化、ファイナライズなど)があります。"、"デストラクタC ++では、削除されようとしているオブジェクトをファイナライズするために自動的に呼び出される操作。"

さらに読む

外部リンク