2017-04-06 20 views
1

私のアプリでメモリリークをデバッグしようとしていましたが(関連記事question参照)、間違った動作が発生しました。このコード(もちろん簡略スニペット)でIServiceProviderガベージコレクション/廃棄

while (true) 
    { 
     using (var context = _serviceProvider.GetRequiredService<IDataContext>()) 
     { 
      Console.WriteLine("Hello"); 
     } 
    } 

メモリ消費が急速を成長させます。

私がサービススポーンをコメントアウトすると、メモリ消費は安定しています。

while (true) 
    { 
     // using (var context = _serviceProvider.GetRequiredService<IDataContext>()) 
     // { 
      Console.WriteLine("Hello"); 
     // } 
    } 

サービスは過渡として登録されました。

私の理解では、usingはサービスの廃棄に関する責任を負います。 var contextwhileの範囲で作成され、新しい反復が始まると破棄する必要があります。

私の最初の考えは、GCはちょうどその仕事を十分にやっていないのですが、消費されるメモリの量が増えると頻度が増えることはありませんでしたか?

なぜ私は間違っていますか?

+0

GCはこれまでに収集されますか? – khargoosh

+0

@khargooshそうすべきではないようです。問題はその理由です。 –

+0

'_serviceProvider'が' IDisposable'を正しく実装していないか、リソースを解放していない可能性はありますか?あなたはいつでも例外を受け取りますか? – khargoosh

答えて

3

問題を解決した後、私は最終的に答えを得ました。要するに、問題はMicrosoft DIコンテナ一時的なサービスを処理せず、参照を保持しているということです。

githubの対応するissueがここにあります。

開発者は、修正のコスト(複雑さとハック感)が利益を上回っているため、修正する予定はありません。

推奨処置はトランジエントの代わりにスコープサービスを使用しています。

ここにコードの例を示します。issueを参照してください。

using (var scope = serviceProvider.CreateScope()) 
using (var context = scope.ServiceProvider.GetRequiredService<IDataContext>()) 
{ ... }