2015-12-25 11 views
21

プログラムが予期せず終了した場合(例外またはプロセスが終了した場合)はどうなりますか?プログラムが終了する場所(または他の場所)はありますか?IDisposableオブジェクトは適切に処理されません。プログラムが予期せずシャットダウンした場合、IDisposableオブジェクトは破棄されますか?

私が求めている理由は、周辺機器と通信するコードを書いているからです。悪い状態になる可能性はないと確信しています。

+0

をあなたは特に「シャットダウン」を意味しますか?電源が切れた場合や未処理の例外がスローされた場合のような意味ですか? –

+0

例外。電源が切れた場合(周辺機器はこの場合はリセットされます)、実行できる合理的なものはありません。私は質問を更新します。 – JSideris

+0

@cFrozenDeathまた、私はプロセスがOS(またはユーザー)によって終了したときを意味します。 – JSideris

答えて

12

原因が例外であり、usingブロックまたはtry catch finallyブロック内で発生した場合は、それは必要に応じて破棄されます。ブロックusingによってキャッチされていない場合、自動的に処理されません(アプリケーションが正常に終了したときには行われません)。

サンプル:

IDisposable d1 = new X(); 

using (IDisposable d2 = new X()) 
{ 
    throw new NotImplementedException(); 
} 

d1.Dispose(); 

d1d2は、通常、配置されていません。いくつかのタイプの例外は、usingブロックの処理といくつかのプログラムのクラッシュを防ぐかもしれません。原因が停電やシステムクラッシュの場合は、どちらも実行できません。

+2

時には、上記のコード( 'd1'と一緒に)のように人々が' Dispose 'を呼び出さないケースを処理するファイナライザ(C#デストラクタ)を書きます。 'Dispose'が呼び出される通常のケースでは、ファイナライザを持つためのパフォーマンスコストを(ほとんどの)回避するために、そのメソッド内部で' GC.SuppressFinalize(this); 'を使います。もちろん、アプリケーション・プロセスがオペレーション・システムによって積極的に抹殺された場合は、これのどれも役立たないでしょう(詳細はここで異なるかもしれません)。 –

+0

私は「オペレーティングシステム」を意味しました。 –

+0

また、killシグナルを受信して​​も、クラッシュは発生しませんが、何もしません。 – Bakuriu

10

プログラムが予期せず終了した場合(たとえば、プロセスを終了するなど)、IDisposable.Disposeメソッドが呼び出されることは絶対にありません。あなたは、そのようなイベントのためにそれに頼らない方がいいでしょう。 Disposeメソッドはコードで手動で呼び出す必要がありますが、CLRが自動的に呼び出すものではありません。

+0

ロックされているとロックされているかのように、あとでファイルにアクセスできますか? –

+8

はい、それがFileStreamの場合、オペレーティングシステムは、プロセスがシャットダウンされたときに基本となるアンマネージハンドルが解放されることを保証します。しかし、これは、Disposeメソッドが呼び出されることを意味しません。オペレーティングシステムは、プロセス終了時にファイルハンドルを再利用する方法を知っているだけです。 –

4

はい、このような状況があります。たとえば、TerminateProcessを呼び出し、Environment.FailFastを呼び出す、または内部CLRエラーが発生すると、すべてのコードが実行されずにプロセスが終了します。そのような状況では、あなたがすることができる最も良いことは、 "ああ"と言うことです。

プロセスが予期せず終了しない場合でも、Disposeを呼び出すことは手動操作です。 Disposeを呼び出すファイナライザを実装しているオブジェクトがガベージコレクトされている場合を除いて、ランタイムを通じて実行されるものではありません。したがって、usingに使い捨て物を包むのを忘れるか、またはオブジェクトを生かしておくメモリリークを引き起こすことを忘れると、別の方法としてDisposeを呼び出すことはできません。

プロセスが終了するとオペレーティングシステムによって信頼できるクリーンアップが実行され、システムオブジェクトに対する開いているハンドルはすべて閉じられます。最後のハンドルが閉じられると、OSやドライバに実装されたクリーンアップが発生します。このクリーンアップコードがドライバの一部ではなく、ユーザープロセスによって呼び出されることになっている場合は、できるだけコードを堅牢にするか、クリーンアップを処理するウォッチドッグプロセスを実装するだけです。

5

コンソールアプリケーションを使用して、非常に簡単なテストでは、廃棄プロセスキルで呼び出されていないことを示しています

class DisposableTest : IDisposable 
{ 
    public void Dispose() 
    { 
     Console.WriteLine("Dispose called"); 
    } 
} 

... 

using (DisposableTest sw = new DisposableTest()) 
{ 
    Thread.Sleep(20000); 
} 

Disposable.Dispose()方法をトリガしませんタスクマネージャでプロセスを強制終了します。 20秒待つ。

既に述べたように、アプリケーションがクラッシュしたり、強制終了されたりすると、使い捨てのオブジェクトに頼らないでください。しかし、例外はそれを引き起こすはずです。 StackOverflowExceptionまたはOutOfMemoryExceptionなどの例外が常にDispose()をトリガーするかどうかは疑問です。

[編集]

はちょうど私の好奇心をテストした:

  • StackOverflowExceptionは終了したプロセスを取得していないので、何のDispose()
  • OutOfMemoryExceptionは廃棄(の通常の通話を可能と呼ばれている)
+0

ありがとうございます。私はちょうどそれをテストしました。 – Alexei

+0

これまでもこれをテストしましたが、これが包括的なテストであるかどうかはわかりません。 – JSideris

2

IDisposableは単なるインターフェイスです。彼らの扱い方には何も特別なものはありません。 IDisposable(明示的にまたはusingブロック経由)でDisposeを呼び出すと、Disposeメソッドの内容が呼び出されます。それは他のオブジェクトのようにガベージコレクションを取得します。

インターフェイスの目的は、明示的にクリーンアップする必要がある管理対象リソースまたは非管理対象リソースを持つ可能性があるタイプのクリーンアップを実装者が定義できるようにすることです。

これらのリソースがすべて管理されている場合、ガベージコレクションで十分であり、実装は最適化のためのものである可能性があります。

管理されていないリソース、または管理されていないリソースに接続している場合は、おそらくガベージコレクションでは不十分です。このため、IDisposableの完全な推奨実装では、ランタイムによる明示的な処分と廃棄(ファイナライザによる)の両方を処理する必要があります。

プロセスのシャットダウンではDisposeが呼び出されず、ファイナライザの実行が保証されないため、プロセスを破壊するだけで十分です。

6

アプリケーションが正しく終了しても、Patrick Hofman氏とAlexei氏の回答クリーンアップに加えて、実行できないことがあります。

Disposeメソッドは、ガベージコレクタがIDisposableインターフェイスを実装するオブジェクトを収集するときには呼び出されません。しかし、GCはファイナライザとも呼ばれるFinalizeメソッドを呼び出します。その中で、Dispose Patternを使ってクリーンアップロジックを書くべきです。もちろん、.Net Frameworkはすべてのファイナライザを実行しようとしますが、実行される保証はありません。

例として、プログラムは非常に長く実行中のファイナライザを持っています。したがって、.Netはプロセスを終了し、メッセージは表示されません。

class FinalizableObject 
{ 
    ~FinalizableObject() 
    { 
     Thread.Sleep(50000); 
     Console.WriteLine("Finalized"); 
    } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     new FinalizableObject(); 
    } 
} 

これは、ネットワークハンドルを解放するなど、長時間かかる操作が原因で発生する可能性があります。

したがって、ファイナライザと使い捨てオブジェクトには決して依存しないでください。しかし、カーネルオブジェクトへの開いているハンドルはすべて自動的に閉じられますので、心配する必要はありません。

私はファイナライザとの回答に加えて、GCについていくつかの興味深い記事読むことをお勧めします:何

  1. Everybody thinks about garbage collection the wrong way (Raymond Chen)
  2. When everything you know is wrong, part one (Eric Lippert)
  3. When everything you know is wrong, part two (Eric Lippert)
  4. Terminating a Process (MSDN)
+0

非常に良い記事を読む! – JSideris

関連する問題