この記事は機械翻訳されています。英語版の記事を表示するには、[英語] のチェック ボックスをオンにしてください。また、テキストにマウス ポインターを合わせると、ポップアップ ウィンドウに英語のテキストを表示することもできます。
翻訳
英語

Object.Finalize メソッド ()

 

公開日: 2016年10月

オブジェクトがガベージ コレクションにより収集される前に、そのオブジェクトがリソースを解放し、その他のクリーンアップ操作を実行できるようにします。

名前空間:   System
アセンブリ:  mscorlib (mscorlib.dll 内)

protected virtual void Finalize()

Finalize メソッドの使用をオブジェクトが破棄される前に、現在のオブジェクトによって保持されているアンマネージ リソースのクリーンアップ操作を実行します。 メソッドが保護されているためおよび派生クラスを使用またはこのクラスによってのみアクセスできます。

このセクションの内容:

Object クラスの実装を提供しない、 Finalize メソッド、およびガベージ コレクターがから派生した型をマークしていない Object の終了処理をオーバーライドしない限り、 Finalize メソッドです。

型をオーバーライドする場合、 Finalize メソッド、ガベージ コレクターにエントリを追加、型の各インスタンスの終了キューと呼ばれる内部構造体。 ファイナライザーのキューには、すべてのオブジェクトが終了コードを実行したガベージ コレクターが、メモリを再利用できる、マネージ ヒープ内のエントリが含まれています。 ガベージ コレクターを呼び出して、 Finalize 、次の条件下で自動的にメソッド。

  • ガベージ コレクターがオブジェクトをへの呼び出しによって終了処理から除外されている場合を除きには、オブジェクトにアクセスできる、しないことを検出したら、 GC.SuppressFinalize メソッドです。

  • アプリケーション ドメインのシャット ダウン中に、オブジェクトが終了処理の対象でない限りです。 シャット ダウン中、まだアクセス可能であるものオブジェクトが完了します。

Finalize 自動的に 1 回だけ呼び出す特定のインスタンスでオブジェクトが再などのメカニズムを使用して、登録されている場合を除き、 GC.ReRegisterForFinalizeGC.SuppressFinalize メソッドは、後で呼び出されていません。

Finalize 操作には、次の制限があります。

  • ファイナライザーが実行するときに正確な時間は、定義されていません。 クラスのインスタンスを実装、リソースの確定的解放を確実に、 Close メソッドを提供または、 IDisposable.Dispose 実装します。

  • 2 つのオブジェクトのファイナライザーは 1 つのオブジェクトを指す他の場合でも特定の順序で実行する保証されません。 つまり、オブジェクト A は、オブジェクト B を参照している両方ファイナライザーがある場合は、オブジェクト B 可能性があります既にファイナライズされているオブジェクトのファイナライザーの開始時にします。

  • ファイナライザーが実行されているスレッドは、指定されていません。

Finalize メソッドが完了するまで実行されない、または次の例外的な状況ではまったく実行されない可能性があります。

  • 別のファイナライザーが無限にブロックした場合 (、無限ループに移動しようとすることはありませんを取得し、ロックを取得)。 ランタイムがファイナライザーの実行を完了しようとすると、原因別のファイナライザーが呼び出されません場合は、ファイナライザーがブロック無制限にします。

  • 場合は、ランタイムをクリーンアップする機会を与えることがなく、プロセスを終了します。 この場合、ランタイムの最初のプロセスの終了通知は DLL_PROCESS_DETACH 通知です。

ランタイムは、ファイナライズ可能なオブジェクトの数が減少し続けます間だけシャット ダウン中にオブジェクトの終了を続行します。

場合 Finalize またはのオーバーライド Finalize 、例外がスローされると、ランタイムが、既定のポリシーをオーバーライドしているアプリケーションでホストされていない、プロセスとはアクティブなランタイムが終了する try/finally ブロックまたはファイナライザーが実行されます。 この動作は、ファイナライザーが解放またはリソースを破棄できない場合、プロセスの整合性を確保します。

オーバーライドする Finalize など、アンマネージ リソースを使用するクラスのファイル ハンドルまたはデータベース接続にガベージ コレクション中にそれらを使用するマネージ オブジェクトが破棄されたときにリリースする必要があります。

System_CAPS_important重要

場合、 SafeHandle オブジェクトが使用できるアンマネージ リソースをラップするが、推奨される代替セーフ ハンドルの dispose パターンを実装し、上書きしない Finalizeします。 詳細については、次を参照してください。 代わりに、SafeHandle セクションです。

Object.Finalize メソッドは既定では、何しますが、これを上書きする必要があります Finalize のみ必要であれば、アンマネージ リソースを解放するだけです。 メモリを再利用するには、少なくとも 2 つのガベージ コレクションが必要とするために終了操作が実行されている場合は、かなり長くかかる傾向があります。 さらに、オーバーライドする必要があります、 Finalize メソッド参照の型だけです。 共通言語ランタイムは、参照型のみを終了します。 値型にファイナライザーが無視されます。

すべての実装の Finalize が派生型内の基本データ型の実装を呼び出す必要があります Finalizeします。 これは、アプリケーション コードは呼び出しを許可する場合だけ Finalizeします。

System_CAPS_noteメモ

C# コンパイラがオーバーライドを許可していない、 Finalize メソッドです。 代わりに、実装することでファイナライザーを提供する、 デストラクター クラスです。 C# デストラクターは、その基本クラスのデストラクターを自動的に呼び出します。

または独自の構文を実装するために visual C、 Finalize メソッドです。 詳細については、の「デストラクターとファイナライザー」セクションを参照してください。 方法: クラスと構造体 (C++ CLI) 定義および使用します。

ガベージ コレクションは非決定的であるため、ガベージ コレクターがファイナライズを実行したときに正確にするは知りません。 リソースを解放する、すぐにこともできますを実装する、 dispose パターンIDisposable インターフェイスです。 IDisposable.Dispose 実装は、アンマネージ リソースを解放する、クラスのコンシューマーによって呼び出すことができるし、使用することができます、 Finalize アンマネージ リソースを解放するためのメソッドになった場合、 Dispose メソッドは呼び出されません。

Finalize ガベージ コレクション中にクリーンアップされた後 (つまり、オブジェクトにアクセスできるように再度) オブジェクトを復活させる方法を含め、ほとんどすべてのアクションがかかります。 ただし、オブジェクトできますのみ再生できるは 1 回です。 Finalize ガベージ コレクション中に再生されたオブジェクトで呼び出すことはできません。 1 つのアクションがあることの実装 Finalize を渡す必要があります: は例外をスローしません。

信頼性の高いファイナライザーの作成が多くの場合、困難で、アプリケーションの状態に関する仮定をすることはできないためなど、未処理のシステム例外 OutOfMemoryExceptionStackOverflowException ファイナライザーを終了します。 派生したオブジェクトを使用するアンマネージ リソースを解放するには、クラスのファイナライザーを実装するには、代わりに、 System.Runtime.InteropServices.SafeHandle 、アンマネージ リソースをラップするクラスし、ファイナライザーなしの dispose パターンを実装します。 .NET Framework では、次のクラスには、 Microsoft.Win32 から派生した名前空間 System.Runtime.InteropServices.SafeHandle:

次の例では、 dispose パターン オーバーライドする代わりにセーフ ハンドルを使った、 Finalize メソッドです。 定義、 FileAssociation を特定のファイル拡張子を持つファイルを処理するアプリケーションのレジストリ情報をラップするクラス。 として返される 2 つのレジストリ ハンドル out Windows によってパラメーター RegOpenKeyEx に関数呼び出しが渡される、 SafeRegistryHandle コンス トラクターです。 型の保護 Dispose メソッドを呼び出します、 SafeRegistryHandle.Dispose これら 2 つのハンドルを解放します。

using Microsoft.Win32.SafeHandles;
using System;
using System.ComponentModel;
using System.IO;
using System.Runtime.InteropServices;

public class FileAssociationInfo : IDisposable
{
   // Private variables.
   private String ext;
   private String openCmd;
   private String args;
   private SafeRegistryHandle hExtHandle, hAppIdHandle;

   // Windows API calls.
   [DllImport("advapi32.dll", CharSet= CharSet.Auto, SetLastError=true)]
   private static extern int RegOpenKeyEx(IntPtr hKey, 
                  String lpSubKey, int ulOptions, int samDesired,
                  out IntPtr phkResult);
   [DllImport("advapi32.dll", CharSet= CharSet.Unicode, EntryPoint = "RegQueryValueExW",
              SetLastError=true)]
   private static extern int RegQueryValueEx(IntPtr hKey,
                  string lpValueName, int lpReserved, out uint lpType, 
                  string lpData, ref uint lpcbData);   
   [DllImport("advapi32.dll", SetLastError = true)]
   private static extern int RegSetValueEx(IntPtr hKey, [MarshalAs(UnmanagedType.LPStr)] string lpValueName,
                  int Reserved, uint dwType, [MarshalAs(UnmanagedType.LPStr)] string lpData,
                  int cpData);
   [DllImport("advapi32.dll", SetLastError=true)]
   private static extern int RegCloseKey(UIntPtr hKey);

   // Windows API constants.
   private const int HKEY_CLASSES_ROOT = unchecked((int) 0x80000000);
   private const int ERROR_SUCCESS = 0;

    private const int KEY_QUERY_VALUE = 1;
    private const int KEY_SET_VALUE = 0x2;

   private const uint REG_SZ = 1;

   private const int MAX_PATH = 260;

   public FileAssociationInfo(String fileExtension)
   {
      int retVal = 0;
      uint lpType = 0;

      if (!fileExtension.StartsWith("."))
             fileExtension = "." + fileExtension;
      ext = fileExtension;

      IntPtr hExtension = IntPtr.Zero;
      // Get the file extension value.
      retVal = RegOpenKeyEx(new IntPtr(HKEY_CLASSES_ROOT), fileExtension, 0, KEY_QUERY_VALUE, out hExtension);
      if (retVal != ERROR_SUCCESS) 
         throw new Win32Exception(retVal);
      // Instantiate the first SafeRegistryHandle.
      hExtHandle = new SafeRegistryHandle(hExtension, true);

      string appId = new string(' ', MAX_PATH);
      uint appIdLength = (uint) appId.Length;
      retVal = RegQueryValueEx(hExtHandle.DangerousGetHandle(), String.Empty, 0, out lpType, appId, ref appIdLength);
      if (retVal != ERROR_SUCCESS)
         throw new Win32Exception(retVal);
      // We no longer need the hExtension handle.
      hExtHandle.Dispose();

      // Determine the number of characters without the terminating null.
      appId = appId.Substring(0, (int) appIdLength / 2 - 1) + @"\shell\open\Command";

      // Open the application identifier key.
      string exeName = new string(' ', MAX_PATH);
      uint exeNameLength = (uint) exeName.Length;
      IntPtr hAppId;
      retVal = RegOpenKeyEx(new IntPtr(HKEY_CLASSES_ROOT), appId, 0, KEY_QUERY_VALUE | KEY_SET_VALUE,
                            out hAppId);
       if (retVal != ERROR_SUCCESS) 
         throw new Win32Exception(retVal);

      // Instantiate the second SafeRegistryHandle.
      hAppIdHandle = new SafeRegistryHandle(hAppId, true);

      // Get the executable name for this file type.
      string exePath = new string(' ', MAX_PATH);
      uint exePathLength = (uint) exePath.Length;
      retVal = RegQueryValueEx(hAppIdHandle.DangerousGetHandle(), String.Empty, 0, out lpType, exePath, ref exePathLength);
      if (retVal != ERROR_SUCCESS)
         throw new Win32Exception(retVal);

      // Determine the number of characters without the terminating null.
      exePath = exePath.Substring(0, (int) exePathLength / 2 - 1);
      // Remove any environment strings.
      exePath = Environment.ExpandEnvironmentVariables(exePath);

      int position = exePath.IndexOf('%');
      if (position >= 0) {
         args = exePath.Substring(position);
         // Remove command line parameters ('%0', etc.).
         exePath = exePath.Substring(0, position).Trim();
      }
      openCmd = exePath;   
   }

   public String Extension
   { get { return ext; } }

   public String Open
   { get { return openCmd; } 
     set {
        if (hAppIdHandle.IsInvalid | hAppIdHandle.IsClosed)
           throw new InvalidOperationException("Cannot write to registry key."); 
        if (! File.Exists(value)) {
           string message = String.Format("'{0}' does not exist", value);
           throw new FileNotFoundException(message); 
        }
        string cmd = value + " %1";
        int retVal = RegSetValueEx(hAppIdHandle.DangerousGetHandle(), String.Empty, 0, 
                                   REG_SZ, value, value.Length + 1);
        if (retVal != ERROR_SUCCESS)
           throw new Win32Exception(retVal);                          
     } }

   public void Dispose() 
   {
      Dispose(true);
      GC.SuppressFinalize(this);
   }   

   protected void Dispose(bool disposing)
   {
      // Ordinarily, we release unmanaged resources here; 
      // but all are wrapped by safe handles.

      // Release disposable objects.
      if (disposing) {
         if (hExtHandle != null) hExtHandle.Dispose();
         if (hAppIdHandle != null) hAppIdHandle.Dispose();
      }
   }
}

次の例では、あることを確認、 Finalize オブジェクトを上書きするときに、メソッドが呼び出された Finalize は破棄されます。 なお、運用アプリケーションで、 Finalize オブジェクトによって保持されているアンマネージ リソースを解放するメソッドをオーバーライドするとします。 なお、c# の例にオーバーライドする代わりにデストラクターが提供する、 Finalize メソッドです。

using System;
using System.Diagnostics;

public class ExampleClass
{
   Stopwatch sw;

   public ExampleClass()
   {
      sw = Stopwatch.StartNew();
      Console.WriteLine("Instantiated object");
   } 

   public void ShowDuration()
   {
      Console.WriteLine("This instance of {0} has been in existence for {1}",
                        this, sw.Elapsed);
   }

   ~ExampleClass()
   {
      Console.WriteLine("Finalizing object");
      sw.Stop();
      Console.WriteLine("This instance of {0} has been in existence for {1}",
                        this, sw.Elapsed);
   }
}

public class Demo
{
   public static void Main()
   {
      ExampleClass ex = new ExampleClass();
      ex.ShowDuration();
   }
}
// The example displays output like the following:
//    Instantiated object
//    This instance of ExampleClass has been in existence for 00:00:00.0011060
//    Finalizing object
//    This instance of ExampleClass has been in existence for 00:00:00.0036294

For an additional example that overrides the M:System.Object.Finalize method, see the M:System.GC.SuppressFinalize(System.Object) method.

ユニバーサル Windows プラットフォーム
8 以降で使用可能
.NET Framework
1.1 以降で使用可能
ポータブル クラス ライブラリ
サポート対象: 移植可能 .NET プラットフォーム
Silverlight
2.0 以降で使用可能
Windows Phone Silverlight
7.0 以降で使用可能
Windows Phone
8.1 以降で使用可能
トップに戻る
表示: