Aspnetcore: Asp.netCoreがガベージを収集しない

作成日 2017年03月21日  ·  136コメント  ·  ソース: dotnet/aspnetcore

Asp.netコアがガベージを収集していないように見える理由がわかりません。 先週、Webサービスを数日間実行しましたが、メモリ使用量は20GBに達しました。 GCが正しく機能していないようです。 そこで、これをテストするために、文字列の大規模なコレクションを返す非常に単純なWebメソッドを作成しました。 アプリケーションは124MBしか使用していませんでしたが、Webメソッドを呼び出すたびに、メモリ使用量は411MBに達するまでどんどん高くなっていきました。 Webメソッドを呼び出し続けていたら、もっと高くなっていたでしょう。 しかし、私はテストをやめることにしました。

私のテストコードはこれでした:

`

[HttpGet]
publicasyncタスク> TestGC(){
const string message = "TEST";
Enumerable.Repeat(message、100000000);を返します。
}
`

何かを見落としているかもしれませんが...私の理解では、このメソッドを呼び出すたびにメモリ使用量が増えるわけではありません。 オブジェクトが作成されてUIに送信されたら、メモリが解放されているはずです。

下のスクリーンショットからわかるように、GCが呼び出された後でも、メモリは解放されませんでした。
netcorescreenshot

助けてくれてありがとう!
ジェイ

investigate

最も参考になるコメント

これに関するニュースはありますか? Core 2 over Net Frameworkを使用していますが、これはまだ発生しています。 _Controller_を呼び出すたびに、使用されるメモリが増加しますが、ダウンすることはありません。 (_私はWebApiテンプレートを使用しました_)

全てのコメント136件

@rynowak

何かを見落としているかもしれませんが...私の理解では、このメソッドを呼び出すたびにメモリ使用量が増えるわけではありません。 オブジェクトが作成されてUIに送信されたら、メモリが解放されているはずです。

大きなオブジェクトのヒープがここであなたを噛んでいる可能性があります。 サイズが85KBを超えるオブジェクトを割り当てると、LOHに配置され、圧縮されることはめったにありません。 詳細については、 http://stackoverflow.com/questions/8951836/why-large-object-heap-and-why-do-we-care (またはhttps://github.com/dotnet/coreclr/blob/master)を参照してください。 /Documentation/botr/garbage-collection.md#design-of-allocator(さらに深く知りたい場合)。

Asp.netコアがガベージを収集していないように見える理由がわかりません。 先週、Webサービスを数日間実行しましたが、メモリ使用量が20GBに達しました

そのような大きなオブジェクトを作成するために、あなたのサービスは何をしていますか? 大きくなりすぎる前にメモリダンプを取得してみてください。これにより、どのオブジェクトが付着しているのか、なぜ保持されているのかが明確に示されます(Visual Studioを使用して、ダンプや、windbgやperfviewなどのより高度なツールを確認できます)。

Enumerable.Repeatを呼び出すのではなく、最初から配列を割り当ててみてください
または、GCSettings.LargeObjectHeapCompactionMode(.Net Standardでサポート)を使用してメモリを圧縮します

返信してくれた@davidfowl@MhAllanに感謝します。 しかし、この例は不自然なものでした。 スクリーンショットを撮れるように、かなりの量のメモリを使用するものが欲しかったのです。 真実は、これは問題のオブジェクトのサイズに関係なく、どのアプリケーションでも発生しているということです。 そして、あなたの質問@davidfowlに答えるために、私のサービスは、dapperを使用してデータベースからデータを取得し、結果のオブジェクトを返すだけでした。 これは、呼び出しごとに1行のデータでした。 そのため、メモリがその量まで増加するまでに数日かかりました。 この特異性に出くわしたとき、私は実際にDBをテストしようとしていました。 メソッドを何度も何度も呼び出し続けるときに、小さなコンソールアプリを作成しました。

@zorthgoそれはDapperではないことを確認しますか? PHPのようにSQLスクリプトに直接パラメーターを挿入してスクリプトを作成すると、多くのキャッシュされたSQLスクリプトが作成されます。 これがDapperのやり方です
https://github.com/StackExchange/Dapper/blob/fe5c270aceab362c936456087a830e6fe1603cac/Dapper/SqlMapper.cs
メモリプロファイラーを使用して、割り当てられたメモリへの参照を保持しているものを確認する必要があります。 Visual Studio 2017は、アプリへの複数の呼び出しの前後にメモリからいくつかのスナップショットを取得し、それらを比較するのに役立つはずです。

@zorthgoはい私もこれを見ました。 .netコアコンソールアプリでservicestackを使用していましたが、APIを呼び出すたびに、メモリ使用量が50MBも大幅に増加しました。 VS2017のバグだと思いましたが、タスクマネージャーでの使用率が高いことを確認しました。 zorthgoがapiを呼び出すだけで述べたように、メモリ使用量は大幅に増加し、メモリを解放しないようです。

これは、.NETCore上のASP.NETCoreでのみ発生しますか、それとも.NETFramework上のASP.NETCoreの問題ですか?

MVC 5(System.Web上)を使用して同様のアプリケーションを作成し、同じ動作が見られないことを確認できますか?

現在の状態では、この問題から進展することはできません。

私のインスタンスでは、ターゲットフレームワーク.NetCoreApp 1.1のみを使用しており、コンソールアプリは共有プロジェクトのオブジェクトモデルを参照していました。

これが誰かを助けるかどうかわからない。 hellorequestを呼び出すサンプルアプリ。 このアプリでは、起動メモリは85 MBですが、繰り返しリクエストすることで、メモリ使用量を約145MBに増やすことができました。 時々125mbにフォールバックしますが、その後はそこに留まります。 私は.NetCoreコンソールアプリに慣れていないため、これが正常な動作であるかどうかはわかりません。 私はいつも、何か間違ったことをしている、または正しくインスタンス化していないと思っていました。

https://drive.google.com/open?id=0B0Gm-m-z_U84TU5keWFTMzc1ZWc

3000〜5000人のアクティブユーザーで本番環境に展開されたAsp.Net Coreアプリケーションで同じ問題に直面しています。昨日、サーバーのメモリが15GBに増加しました...私はまだ3時間ごとにAppPoolを再循環するようにIISを構成する必要がありました問題が何であるかを理解してみてください。

誰かがメモリダンプを取り、特定のアプリケーションですべてのメモリを消費しているものを調べましたか?

@davidfowl @Pinox
私は大企業で働いており、ASP.NET Coreを使用して新しいプロジェクトを開始したいと考えていますが、この問題を目にしたとき、私は恐れていました:心配:。 これは重大な問題であり、プロジェクトのライフサイクルを妨げる可能性があります。

では、ASP.NETCoreまたは.NETCore(CoreCLR)に関連していますか? Full .NET(4.6)をターゲットにするので、私は質問しています。

私の場合、 @ ikourfalnは、.netコアコンソールアプリ、servicestack(.netコアバージョン)、およびkestrelを使用していました。 奇妙なことに、メモリ使用量がレベルに達すると、突然停止し、再び増加しなくなります。 少量のサンプルを使って自分の側でテストし、動作を確認するのが最善だと思います。

おそらく、 @ zorthgoは、そのメモリ内で同様の動作が特定のレベルで使用され、それが私が見ている動作であるため、増加を停止するのを確認できるかどうかを確認できます。 サンプルアプリを更新して@zorthgoの例を含めましたが、メモリが不足しているのがわかりません。 上昇しますが、最終的には停止します。

ソースを少し変更しました:

パブリックオブジェクトAny(TestGCリクエスト)
{{
const string message = "TEST";
Enumerable.Repeat(message、100000);を返します。
}

@Pinox
ありがとう、私は私の側の行動をチェックします。

2.0のこのバグはどうですか?

これに関するニュースはありますか? Core 2 over Net Frameworkを使用していますが、これはまだ発生しています。 _Controller_を呼び出すたびに、使用されるメモリが増加しますが、ダウンすることはありません。 (_私はWebApiテンプレートを使用しました_)

やあ、

ASP.NET Core 2でも同じ問題が発生します。メモリダンプを取得して、分析を試みました。 私が見たところ、問題はOPが言った通りです。 私のアプリケーションは約75MBの割り当てから始まり、すぐに最大750MBになり、そのうち608MBは「.NETに割り当てられた未使用のメモリ」です。

アプリ開始時の最初のスナップショット:
image

3分と100リクエスト後の2番目のスナップショット:
image

また、同じ問題に直面しています。コントローラーが大量のデータを処理しているため(設計が不適切で、まもなく置き換えられます)、このコントローラーを呼び出すたびにメモリが増大します。 メモリは減少しますが、40〜50%しか減少しません(ゲイン50 Mb、30〜35 Mb減少)。呼び出しごとに、メモリは毎回10〜15Mbの範囲で増加します。 サービスはサービスファブリック内でホストされます。

次の組み合わせを使用して、本番サービス(20〜100 req / s)で同様の問題が発生しているようです。

  • ASP.NET Core 2.0.4
  • ServiceStack.Core 1.0.44
  • SkiaSharp 1.59.2
  • Docker v17.09.0-ce、Ubuntu16.04x64でafdb6d4をビルドします
  • x4サーバー@40CPU、128GBメモリ
  • サーバーGCは真です
  • 各Dockerコンテナは、12k(mhz)cpu共有、8GBRAMに設定されています

アプリケーションには、フロントエンドWebサーバーとワーカーがあります(それぞれ下のグラフに示されています)。

Webサーバー(過去6時間)
screen shot 2018-01-13 at 1 06 24 pm

労働者(最後の6時間)
screen shot 2018-01-13 at 1 07 55 pm

サービスがオブジェクトストレージプロキシとして機能し、その結果、オブジェクトをLOHに配置するため、どちらも大きなバイト配列を利用します。 私の質問は、これは現時点で.NET Coreの既知の制限ですか? LOHが完全にクリーンアップまたは断片化されていないようです。

そうは言っても、典型的なWeb APIオブジェクトがクリーンアップされるため、SOHは正常に機能しているようです。 助言がありますか? セットアップに問題がありますか? コードを分析しましたが、明白なメモリリークは見つかりませんでした。また、ServiceStackライブラリ以外で特別なものを使用していません。

@sebastienros-これについて何か考えはありますか? システムで同様の動作を観察しましたか?

  • これは2.1でのみ測定します。2.0でも同じものを追加することを検討します。
  • すべてのコメントは、言及されたLOHの問題に関連しているようです。これは、アプリケーションで考慮し、可能な限り大きなアレイをプールする必要があります。

@sebastienros 、いくつかの質問:

  1. Antsプロファイラーを使用してメモリ使用量を測定したところ、LOHの断片化は検出されませんでした。 アプリケーションでLOHフラグメンテーションの問題が発生しているかどうかを確認するにはどうすればよいですか?
  2. .netコア2.1での結果はどうなりますか? KestrelがSpanを使用しているため、問題は解決しましたか
  3. アレイをプールできない場合はどうなりますか?回避策を提供できますか? GCSettings.LargeObjectHeapCompactionMode.CompactOnceを使用する必要がありますか?

.netコア2.1での結果はどうなりますか? KestrelがSpanを使用しているため、問題は解決しましたか?

私たちは個人的に、問題がケストレルにあるという証拠を見たことがありません。 それでもアプリケーションの問題のようです。

アレイをプールできない場合はどうなりますか?回避策を提供できますか? GCSettings.LargeObjectHeapCompactionMode.CompactOnceを使用する必要がありますか?

@jkotas @ Maoni0ここに何かアドバイスはありますか?

同じ問題が発生したかどうかを調べるにはどうすればよいですか? @sinapisが説明しているように、レッドゲートメモリプロファイラーによるLOHはほとんど空ですが、それでも1人のユーザーに対して1GB以上の簡単な使用が可能です。

トレースを収集し、perfviewを使用して分析します。 .NETメモリリークを追跡する方法については、Vanceなどによるチュートリアルが多数あります: https ://www.bing.com/search?q = .NET%20memory%20leak%20perfview。

https://github.com/dotnet/coreclr/blob/master/Documentation/project-docs/linux-performance-tracing.mdには、トレースを収集するためのLinux固有の手順があります。

メモリリークがなく、GCが必要なメモリをより多く保持していると思われる場合は、次のことを試してください。

  • WindowsジョブオブジェクトまたはDockerコンテナのメモリ制限を使用して、プロセスが使用できるメモリの量を制限します。 GCはこれらの制限を考慮に入れ、制限に近づくとより積極的に実行されます。
  • または、サーバーGCからワークステーションGCに切り替えます。 サーバーGCのピークワーキングセットがはるかに高いことは珍しいことではありません。 ワークステーションのピークワーキングセットは低くなりますが、スループットも低くなります。

やあ、

実稼働環境の.NetCoreWebAPIでも同じような問題が発生していると思います。

アプリケーションは、.NetCore2.0.3を搭載したWindowsServer2016で実行されています。 このマシンは、28個のCPUコアと24GBのRAMを備えたHyper-VVMです。 IISアプリケーションプールを十分な頻度でリサイクルしないと、最終的には使用可能なすべてのメモリを使用することになります。 アプリケーションが大量のメモリ(システムメモリ全体の95%以上)を使用し始めると、CPU使用率も大幅に増加します(2%から70%になることもあります)。 OOM例外がトリガーされるかどうかはわかりませんが、発生する前に常にプールをリサイクルします(私が見た最大メモリ使用量は、dotnet.exeによって使用されるメモリの98%でした)。

「.NetMemoryPorfiler」(SciTechソフトウェア)を使用して本番メモリダンプを分析すると、次のことがわかります。
image

この分析が正しければ、メモリの約95%が「オーバーヘッド>未使用」になります。 このメモリプロファイラーエディタがこのカテゴリを(フォーラムで)どのように説明しているかを次に示します。
_「オーバーヘッド->未使用」は、マネージヒープの.NETランタイムによってコミットされたメモリです。 現在は使用されていませんが、将来のインスタンス割り当てに使用できます。 コミットされたメモリを保持するか、OSに解放するかを決定するために、ランタイムが使用するルールはたくさんあります。 使用可能なメモリ、割り当てパターン、プロセッサの数、サーバーGCが使用されているかどうかなどの要因によって異なります。_

@jkotas推奨事項(Windowsジョブオブジェクト、およびワークステーションGCへの切り替え)を適用し、結果をお知らせします。 私が持っている本番メモリダンプから他の有用な情報を抽出できるかどうか教えてください。

ありがとう

@sinapis @ ronald7
問題を示すアプリを共有できる人はいますか? 再現できれば、理由を見つけるか、少なくともコードを1つずつ削除して、最小限の再現を分離することができます。

@sebastienrosアプリを共有できませんが、 PerfViewセッション+メモリダンプからセッションを共有できます。
説明:ASP.NET Core 2 Web APIを使用しており、200人のユーザーがすべて同じリクエストを10秒間送信する負荷テストを作成しました。 全体で775件のリクエストが処理されました。

このアプリは、タスクマネージャーでほぼ1 GBのメモリ使用量に跳ね上がり、その状態を維持しました。 ダンプを見ると、約18MBを数えることができます。

image

では、問題は、ほぼ1GBがどこに行ったのかということです。

@sinapisありがとう

説明している動作は予期しないものではありません。GCはピーク負荷時に必要に応じてメモリを割り当て、時間の経過とともに解放します。 これはGCサーバーモードであり、通常はアイドル期間が解放されてアプリのパフォーマンスに影響を与えないように待機します。 予約するメモリの量は、システムで使用可能なメモリの合計によって異なります。

それが増え続けるならば、私たちは間違いなく問題を見るでしょう。 これ以上リクエストを送信せずにアプリを実行すると、メモリ使用量が減少すると思います。

システムメモリの大部分を消費するまで同じことを実行できますか? または、少なくともそれが継続的に成長していることを示すのと同じ負荷で十分な長さですか? 私はまだあなたの現在のダンプを見ていきます。

また、ジョブ中およびジョブの終了時にダンプを取ることができるので、詳細を確認できます。

こんにちは@sebastienros

残念ながら、アプリもメモリダンプも共有できませんが、ダミーのアプリケーション(同じアーキテクチャと依存関係)を作成し、同じマシンで実行します。この動作を再現できる場合は、これを共有します。 メモリダンプから抽出できる有用な情報があれば教えてください。

1台の本番サーバーでGCモードを_server_から_workstation_に更新しました。メモリ使用量に変更があった場合は、数時間後にお知らせします。

また、別のテストも実行しました。4つの仮想マシンで、ロードバランサーの背後でアプリケーションを実行しています。 マシンの1つをロードバランサープールから削除した後、dotnet.exeによって使用されるメモリは減少せず、30分後も同じレベルのままでした。 (ただし、アプリケーションはまだいくつかの要求を処理していました。30秒ごとにダミーエンドポイントでSCOMによって送信された1つの要求)。 メモリは解放されず、システムに戻されませんでした。

ありがとう

@sinapis私はあなたのETWトレースを見ました。 それは私には不可解です-あなたは最後に誘発されたgen2GCでほとんど生き残れませんでしたが、それでも私たちはそれだけのメモリをコミットし続けることを選択しました。 アプリケーションはエッジケースのようです(ほとんどの場合、LOH割り当てのためにバックグラウンドGCのみを実行しました)-そこにいくつかのアカウンティングエラーがあるのではないかと思います(別の可能性は報告された数値のエラーですが、すでにコミットしていることを確認した場合は、可能性は小さい)。 あなたが私と共有できる何かで再現できれば、それは素晴らしいことです。 それ以外の場合は、GCからのログを使用してアプリを実行できる場合(それを実行するコミットを提供できます)も役立ちます。

@Maoni0はGCロギングを有効にする方法を共有してください
会計上の誤りを反証するために私に提供してほしい他のデータがある場合は、私があなたに何を提供すべきか、そしてどのように提供すべきかを私に知らせてください(多分perfviewにもっとデータを収集するように言ってください?)
最小限の再現を作成してみますが、問題がどこにあるのかわからないため、成功するかどうかはわかりません。

@sebastienrosうまくいけば、今日はより多くのメモリ消費を伴う別のダンプを提供します

こんにちは@ sebastienros @Maoni0

ワークステーションGCモードでアプリケーションを12時間実行しましたが、同じ結果になりました。 また、単一の本番ノードで.Net 2.1 Preview 2を使用してアプリケーションを1時間再コンパイルしました。結果をお知らせしますが、現在のところ、プロセスでは2GB以上のRAMが使用されています。

image

この同じマシンでPerfViewを実行していて、GCダンプを収集しています。OneDriveリンクを送信できるメールアドレスはありますか。残念ながら、このスレッドで直接共有することはできません。

それが役立つ場合は、より多くのメトリックまたはGCログを収集することもできます。 ありがとう

@ ronald7 _redacted_ @ Maoni0に転送できます

こんにちは@ sebastienros @Maoni02つのPerfViewgcdumpとVMMapファイルを含むメールを送信しました。これがお役に立てば幸いです。 私の側では、ダミーのアプリケーションを使用して、このメモリ使用量の多い動作を再現しようとしています。

ありがとう!

私も同じ問題を経験しています。 ガベージコレクションは決して起こりません! スクリーンショットは、かなり単純なdotnetコアWebAPIアプリを使用して約50のリクエストを実行した後のメモリ使用量を示しています。

memory-profile2

Ubuntu16.04で実行されているASP.NETCoreアプリを1.1から2.0にアップグレードしたところ、この問題が発生しました。 これはかなり深刻で、OOMエラーが原因でカーネルがアプリを頻繁に強制終了するため、1.xにダウングレードするかどうかを検討しています。 まったく読み込めないページがいくつかあります。Kestrelを再起動した後でも、アプリは1回のリクエストですぐに使用可能なメモリを使い果たします。 サーバーをアップグレードすることを考えましたが、使用可能なすべてのメモリを使用するASP.NET Coreアプリに関するここでのコメントに基づいて、それが役立つことを期待していません。 私たちのスタックは基本的にASP.NETMVCコア+EFコアです...それほど派手なものはありません。 時間があれば、問題を再現するためのサンプルを作成しようとします。スタックが単純であることを考えると、それほど難しいことではないと思います。

FWIW、私がアップグレードしたシステムにも.NET Coreコンソールアプリがあり、2.0アップグレード後はメモリの問題がないように見えるので、これは間違いなくASP.NETCore関連の問題のようです。

おそらく関連している: https ://github.com/aspnet/KestrelHttpServer/issues/2214

@danports GC.Collect()を呼び出して、メモリ使用量が劇的に減少するかどうかを確認しましたか? それは私たちがどこから始めるべきかについての手がかりを私たちに与えるでしょう。 GC.Collect()(またはGC.Collect / GC.WaitingForPendingFinalizers / GC.Collect sequent)でメモリ使用量を大幅に減らすことができない場合は、ライブで必要なメモリが多すぎて、GCがそれを再利用できないことを意味します。

@Maoni0まだ試していません。 時々メモリ使用量が減少するので、私の問題はGCにあるとは思いません-.NET Core 2.0アプリは、で実行されていたときと比較して、約2〜3倍のメモリを消費しているようです。 NETCore1.1。 😞

今のところ.NETCore1.1にダウングレードしましたが、後で.NET Core 2.1がリリースされた後など、時間があれば再検討します。 (2.0で問題が山積みになりましたが、これはそのうちの1つにすぎませんでした。)

GC.Collect()は役に立ちません。 200kintのディクショナリを返す1つのコントローラーを持つ非常に単純なASP.NETCore2.0および2.1WebAPIを試しました。 アプリがこれ以上メモリを使用しなくても、割り当てられたメモリはリクエストごとに増え続けます。

@Serjsterが200Kの整数(4B)を返すと、800KBかかります。 この場合、このコメントで説明されている問題が発生しています: https ://github.com/aspnet/Home/issues/1976#issuecomment -289336916

この場合、配列プールを使用して、リクエスト間でそれらを再利用する必要があります。

また、コードが64ビットモードで実行されている場合、ポインターを含む配列/リストなどは32ビットの2倍のサイズになることも知っておくとよいでしょう。 私が正しく覚えていれば、フルフレームワークはデフォルトで64ビットOSで32ビットのCPUコードを実行します。 そのため、コードを移行する人々が誤ってLOHの問題にぶつかる可能性があります。

私は@Serjsterを使用していますが、これが私が見つけたものです。 asp.netコアを使用してバニラWebAPIプロジェクトを作成すると(最新のテストでは2.1を使用しました)、診断ツールを実行すると(または、コードで設定されているプロセスの作業メモリを確認すると)、バイト数が返されることに気付きます。エンドポイントに到達しても上昇し続けます。 たとえば、辞書を返す単一のWebAPIエンドポイントがある場合20,000個のアイテムが含まれていると、次のようになります。

  1. コントローラメソッドに最初にアクセスすると、プロセスメモリは83MBになります。
  2. 数秒待ってから、2回目の訪問で86MBに移動します。
  3. 数秒待つと、3回目の訪問は90MBに移動します。
  4. 再び-94MB。
  5. これをn回実行すると、最終的に約304MBに達します。 これを行うと、横ばいになります。

戻りオブジェクトが異なるサイズのオブジェクトである場合、上記のすべての数値は(平準化量を含めて)ちょうど大きい/小さいですが、成長パターンは同じです(つまり、多くの要求の後に横ばいになるまで成長します) 。

メソッド呼び出しにGC.Collectを追加すると(したがって、すべてのリクエストで発生するため、のレベルははるかに低くなりますが、横ばいになるまで成長期間があります。

もう1つの興味深い詳細点は、スナップショットを実行するときのオブジェクトの数とヒープサイズが、訪問するたびにほとんど変わらないことです。 ただし、プロセスメモリグラフには、ますます多くの数値が表示され続けます(これは、プロセスを取得して作業メモリの設定値を取得した場合にも当てはまります)。

グラフに割り当てられたメモリが表示されているのではないかと思い始めています(このメモリは、asp.netコアの使用量/需要予測ロジックに基づいて増加します)が、これは必ずしもメモリの消費/リークではありません。 でも確認するのに十分なことはわからないので、もっと知識のある人がチャイムを鳴らすことができるのではないかと思います。

編集-re@davidfowlコメント:めったに収集されないものについてのあなたのコメントに関して...これは理にかなっているかもしれません。 しかし、通常どのくらい時間がかかりますか? リクエストの合間に30秒以上進むことができますが、GCが診断チャートのそのメモリ番号を元に戻すことはないようです。 私はここで何かについて無知であると確信していますが、ただ興味があります。

編集2-davidが上に投稿したSOリンクをより詳細に読んだので、これは間違いなく私たちが見ている問題だと思い始めています。 メモリが限られている環境で実行している場合(安価であるためにこれが表示されている開発環境にあります)、これに問題が発生します。

編集3-1つの長引く質問。 プロセスメモリが一貫して増加しているのに、これがLOHの問題である場合、ヒープサイズが増加しないのはなぜですか? 実は今、これは理解できるかもしれません。 ヒープは使用済みメモリです。 プロセッサに割り当てられたメモリは、使用済みメモリと未使用のフラグメント化されたメモリブロックです。

@RemyArmstro Dictionary<int, int>SortedDictionary<int, int>に変更できますか? 辞書はおそらく連続メモリを割り当てており、すべてのエントリに追加のデータを追加することさえあります。 SortedDictionaryが実装されている方法では、1つの大きな割り当てではなく、多くの小さな割り当てが行われます。

編集:応答出力ストリームに直接ではなく文字列にシリアル化する場合は、LOH割り当ても発生する可能性があります。

@wanton7あなたの回答は要点を欠いています。 辞書は氷山の一角にすぎません。 リストや配列などを使用でき、それらはすべて同じことを行います。 しかし、LOHがこれを引き起こしていると指摘されたように、それがそうであるように聞こえますが、この動作はおそらく問題ありませんか? これを除いて、メモリが不足したときに何が起こるかなど、いくつかの懸念される副作用がありますか? アプリがクラッシュしますか?

@Serjsterok私はあなたがこれが起こっているほんの小さなケースを持っていると思いました。 私にとって、大きなリスト、このような配列があり、バイナリでない場合は1回のAPI呼び出しでこれだけのデータを送信することは非常に珍しいことです。 通常、ある種のWeb APIがあり、そこからデータを取得する場合は、ページングを使用します。 クライアント側に10000エントリを送信するべきではありません。
しかし、このような問題がたくさんあり、APIの動作を変更する方法がない場合は、独自のチャンク化されたリストと辞書の実装を作成する必要があると思います。 本当にこれほど大きな配列を使用している場合は、それらをチャンクリストに置き換えるか、アプリケーションの起動時にそれらをプールしてみてください。

マイクロソフトが、このような状況で誰もが使用できるチャンク化された実装を作成することを望んでいます。

@wanton7またしてもあなたは要点を逃しています。 リストのサイズは関係ありません。 単一のアイテムまたは小さなリストでも、この問題が発生します。

@Serjsterたぶん私は盲目ですが、単一のアイテムまたは小さなリストを送信するとこれが発生すると言ったあなたからの投稿は表示されません。 削除しましたか?

または@RemyArmstroから彼はさまざまなサイズの辞書について話します。 corefxをチェックすると、Dictionaryが配列またはこれらを割り当てます

private struct Entry
{
  public int hashCode;    // Lower 31 bits of hash code, -1 if unused
  public int next;        // Index of next entry, -1 if last
  public TKey key;           // Key of entry
  public TValue value;         // Value of entry
}

85000バイトの割り当てによりLOH割り当てが発生するため、intキーとint値の5313エントリの容量を持つディクショナリによりLOH割り当てが発生します。 容量は数やエントリと同じではありません。容量は素数によって拡張されているようです。プライベートディクショナリのプライベートサイズ変更方法を確認してください。 各構造体には追加の割り当てとメモリパディングが含まれる可能性があるため、エントリがさらに少ないとLOH割り当てが発生する可能性があります。

辞書の実装の詳細Dictionary.cs

編集:固定URL

@wanton7ありがとうございます。 私たちは今問題が何であるかを理解していると思います。 これに対する素晴らしい+単純な解決策はありません。 基本的には、それをよりよく認識し、コードの記述方法を調整することになります。 欠点は、この管理されていないメモリがもう少し管理されていると感じ始めることです。 :(最終的に、この割り当て制限に実際に違反する領域はごくわずかかもしれませんが、そのうちの1つはアプリのコアであるため、現在多く見られます。その部分を再考する必要があると思います。監視し、このクリープに気付いた他の領域を探し出してみてください。ありがとうございます。

実際、まもなく同様の状況になり、チャンク化されたIList<T>実装を作成する必要があります。 ビットシフト可能なチャンクにいくつかのサイズを使用するので、インデックス作成にビットシフトとマスクを使用できます。

GC、大きいチャンク、または小さいチャンクのどちらがより有益か知りたいですか? 1KBから64KBのサイズから。 チャンクが小さいほど、GCの参照が多くなりますが、チャンクが大きいほど、圧縮と断片化が悪化する可能性があります。

あなたの理解は正確に正しいです-私は大きすぎないサイズで行きます。 おそらく4k/8kを試してみてください。

@ Maoni0ありがとうございます!

私は4KBを選択したので、Monoでコードを実行した場合でも、厄介な驚きはありません。 http://www.mono-project.com/docs/advanced/garbage-collector/sgen/working-with-sgen/を読むと、LOHしきい値はMonoではわずか8000バイトであることがわかりました。

この問題の進展はありますか?

ヒープサイズが同じ(または減少)のままであるにもかかわらず、プロセスメモリが増加し続けるという同じ問題が観察されています。

@sebastienrosこれをもう一度見ていただけますか? シナリオをさらに調査するのに役立つ詳細な手順を提供できるかもしれません。

これが私たちの状況で考慮すべきいくつかの項目です:

  • 1000個の整数値が格納されたDictionary<int, int>オブジェクトのみを返します。 それ以上のものはありません。
  • プロジェクトを.NETCore2.0->2.1から変換しました
  • この問題はMSVisualStudio2017で発生しています

次のようにコーディングします。

    public async Task<IActionResult> SampleAction()
    {
        var list = new Dictionary<int, int>();
        for (int n = 0; n < 1000; n++) list.Add(n, n);
        return Ok(list);
    }

再現するには、何らかの形の中程度の負荷をシミュレートする必要があります。 Postmanを使用してすばやくクリックしただけで、この動作を観察できました。 負荷のシミュレーションを停止すると、ヒープサイズが減少するのを確認しましたが、プロセスメモリは同じままでした(GCを強制した場合でも)。

これは私のプロジェクトの1つでも見られますが、.Net Core 2.1(SDK 2.1.302)をターゲットとする新しい.netコアAPIで再作成することもできます。

Visual Studio 15.8.0プレビュー4を使用して作成したサンプルAPIプロジェクトを添付しました。メモリの増加を示すために、.netコアコンソールアプリでデフォルト値のGETエンドポイントを0.5秒ごとにヒットして2つの文字列を取得しました。 プロセスのメモリ使用量は遅いですが、より多くのデータを返すプロジェクトでは、これは急速に増大する可能性があります。

screenshot
WebApplication1.zip

私はスタック交換でこの投稿を見つけました:

https://stackoverflow.com/questions/48301031/why-doesnt-garbage-collector-in-net-core-2-0-free-all-memory

この動作が存在するかどうかを確認するために、リリースモードでアプリケーションのプロファイルを作成した人はいますか? 今日はこれを試してみて、問題が解決するかどうかを確認します。

編集:リリースモードでプロファイリングを試しましたが、問題は解決しません。 GCに、それが効果があるかどうかを確認するように強制します。

image

@chrisaliottaその投稿にリンクしてくれてありがとう、私はその振る舞いに気づいていませんでした。 それが人々が見ているものを説明するかどうかを見るのは確かに興味深いでしょう。

@Eilon @chrisaliottaありがとうございますが、これはこの議論とは関係ありません。 .NETがデバッグモードでメモリを解放しないことはよく知られている動作であり、これが解放モードでのみメモリ消費(および潜在的なリーク)を測定する理由です。 また、リリースモードでも、サーバーGCモードのために、時間の経過とともにメモリがある程度増加することがわかります。 したがって、この例では、2つの異なる理由で何も証明されません。

@sebastienrosでは、 @ beef3333と私が観察している動作は、予想される動作と一致していますか? つまり、ヒープサイズが減少しても、プライベートバイトはどこで上昇したままですか? もしそうなら、空きヒープスペースがあるにもかかわらず、各インクリメンタルリクエストがプライベートバイトを成長させ続けるのは私には奇妙に思えます。

デバッグモードではあります。 ですから、リリースモードを使ってみて、長時間ストレスをかけないでください。 メモリが無期限に増加する場合は、メモリリークが発生しています。 メモリがリサイクルされている場合(かなりの量のメモリが必要な場合でも)、あなたの場合はすべて問題ありません。

リリースモードでアタッチしたのと同じプロジェクトを使用して再度テストしたところ、まったく同じ動作が見られました。

それでは、アプリケーションをテストします。ありがとうございます。

@ beef3333によって提供されたアプリケーションをローカルで2時間、5K RPSのレートで実行しましたが、メモリは安定しています(32GBのマシンでは400MBで、全体で1MBの変動)。 GCは定期的に正しく呼び出されます。 また、時間外に複数のダンプを検査したところ、さまざまなインスタンスが期待どおりに作成および収集されました。 2.1.1を使用しています。

@sebastienrosこれを調べていただきありがとうございます。 このすべてのポイントは次のとおりだと思います。

  • .NET Core Webアプリケーションと一般的なデスクトップアプリケーションでは、メモリ管理の動作が異なります。
  • 開発者は、一定期間の1秒あたりの関数要求(RPS)としての平均メモリ消費量に焦点を当てる必要があります。
  • プライベートバイトの増加は、必ずしもメモリリークを示しているとは限りません。

私が間違っている場合は訂正してください。ただし、.NET Coreは、最速の応答時間を確保するために、平均的な要求に基づいて割り当てられたメモリを増やすようです。 trueの場合、アプリケーションプールがリセットされるまで、この割り当てられたメモリを解放しない可能性が高いと想定しても安全ですか?または、RPSが減少した場合、この割り当てられたメモリは時間の経過とともに解放されますか?

同じ問題。
asp.netwebapiバックエンドサービスがあります。
スタックは、asp.net mvc、autofac、automapper、castle.dynamicproxy、entityframeworkコアです。
すべてのメモリが消費され、サービスがクラッシュします。

バージョンは2.1.0です

@atpyk2.1.1に更新します。 それでも問題が解決しない場合は、そのメモリを保持しているものを実際にプロファイリングする必要があります。 私はhttps://www.jetbrains.com/dotmemory/を使用しましたが、これを実行できる他のツールもおそらくあります。 ラージオブジェクトヒープ(LOH)に実際に割り当てられているものを表示できます。

32ビットモードで実行していますか? ラージオブジェクトヒープの割り当て(最大85000バイトより大きい)は、断片化が原因で32ビットモードでメモリ不足の例外を引き起こす可能性があるためです。 辞書を使用すると、この制限を非常に簡単に乗り越えることができます。 このコメントを確認してくださいhttps://github.com/aspnet/Home/issues/1976#issuecomment-393833505

コードを完全な.NetFrameworkで実行している場合、デフォルトの動作では、32ビットモードで任意のCPUコードが実行されます。 プロジェクト設定から32ビットを優先するのチェックを外すか、サーバーレジストリのレジストリ設定をデフォルトの64ビットに設定する必要があります。

@wanton7ありがとうございます。 私はあなたの解決策を試します。

2.1.2に更新し、win-x64を使用してMicrosoft Azure Webアプリケーションに展開しましたが、効果がありません。 @ wanton7
dotnetcorememory

@atpykは、メモリスナップショットを作成して(dump_および分析(Visual Studio、MemoScope)、どのオブジェクトがすべてのメモリを使用しているか、または単にカウントを増やしているかを確認してください。2つ取得して、時間の経過とともに比較することもできます。

@sabastienros私は、あなた/MSが実際にこれを自分で分析し始めるべきであるという懸念を十分な人々が提起したと信じています。 おそらくこれは意図したとおりに機能していますが、設計に欠陥があります。

私たちのアプリは最終的にメモリが不足してクラッシュし、これはすべて本番Azure環境で実行されます。 これは受け入れられません。

@atpykの場合、メモリリークのように聞こえます。 @sebastienrosが言ったように、あなたの記憶をプロファイリングして、その記憶を維持しているものを確認してください。

1つの質問ですが、ASP.NET Coreを使用していますか? 最初のコメントをもう一度読みましたが、ASP.NETMVCについて言及しています。 ASP.NETMVCとASP.NETCoreは、まったく異なる2つの製品です。 これらの問題とASP..NETCoreのこのリポジトリ。

編集:バージョン番号からは、ASP.NET Coreを使用しているように聞こえますが、確認したかったのです。

.netコアMVCを使用します。 @ wanton7
私は記憶を分析しています。 CastleDynamicProxyがメモリリークを引き起こす可能性があります。
memroy1
memroy2
memroy3
dynamicproxy

@Serjsterは、32ビット.NET Coreで実行され、メモリ不足の例外でクラッシュするプログラムですか? コードが多くのLOH割り当てを行う場合は、おそらくメモリの断片化が原因です。
32ビット環境で実行している場合は、2つの選択肢があります。コードを修正して、LOHを回避するか、64ビット環境に切り替えてください。

私はAzureにあまり詳しくありませんが、少しグーグルした後、このhttps://blogs.msdn.microsoft.com/webdev/2018/01/09/64-bit-asp-net-core-on-azure-appを見つけました

@Serjsterここにあるすべてのレポートが同じであるとは限らないと思います。また、それぞれの異なるケースの妥当性を確認することを好みます。 「私のアプリにメモリリークがあります」のようなものは、それがフレームワークのせいではないので、それぞれの場合に実際のものであることを確認したいと思います。

あなたの場合を例にとると、あなたの記憶が増えている理由に私が答えたと「私は信じています」。 私の説明の後でそれを修正することができましたか? または、問題が解決しなかった場合、この場合、問題を再現するためにローカルで実行できるアプリケーションを提供できますか?

@sebastienros私たちが見つけたのは、メモリ消費量が増加しなかったにもかかわらず、メモリ割り当てが増加し続けたということでした。 ASP.NET Coreは、より多くを取得する必要があることを伝えるためにいくつかのヒューリスティックを実行していることを知っていますが、要求ごとに常にますます多くを割り当てているようです。 この点で私にはほとんど貪欲に見えますが、私は間違っている可能性があります。

いずれにせよ、 @ Serjsterのポイントは、ここには明らかに混乱があるため、このスレッドは成長し続けるということだと思います。 古いASP.NETランド(コア1より前)では、この動作を確認する必要はありませんでした(少なくともこの規模ではありません。実際にはバグ/問題ではないかもしれませんが、多くの人を引き起こしていることは間違いありません。同じ質問を何度も繰り返す。

これまでのように円を描くのではなく、このスレッドを上から下に実際に扱った公式記事があればいいのにと思います。 それが明確になることを願っています。

これまでのように円を描くのではなく、このスレッドを上から下に実際に扱った公式記事があればいいのにと思います。 それが明確になることを願っています。

同感です。 .NET Core 2.1が、以前のバージョンよりもメモリ管理に関して「日和見的」である理由を知っておくとよいでしょう。

@sebastienrosここで問題の概要を教えていただけますか? 81のコメントがあります-私はそれらがすべての問題についてではないという印象を受けています(私はそれらをまったく注意深く読んでいないので、私は間違っているかもしれませんが)。 もしそうなら、ここにすべての個別の問題をリストし、それぞれの再現があるかどうかを確認できますか? 記憶力の増加について言及している人は十分にいます。私たちは、再現を得て、これらが一般的な問題であるかどうかを理解することを正当化すると思います。

もちろん。 私は現在、これらすべてのスレッドを識別し、それぞれのステータスを確認しようとしています。 この単一のスレッドはもはや持続可能ではないため、私は最終的にこの問題を閉じて、各レポートに焦点を当てたより具体的な問題を再開します。 このスレッドでフォローしたい人のために、ここにリンクします。

並行して、すべての推奨事項、既知のメモリの問題(LOB、HttpClientなど)、およびこれらの問題を分析および報告する方法をリストしたドキュメントを作成します。

この問題に注意を払い、メモリリークを事前に検出するために、過去6か月間、AzureでLinuxとWindowsの両方のASP.NETアプリケーションを24時間と7日間継続的に実行してきました。 これらのテストは、すべての反復(毎日または毎週)で最新のASP.NETソースをフェッチします。 RPS、レイテンシ、CPU、メモリ使用量を測定します。 このアプリケーションは、EF Core、MVC、およびRazorを使用し、50%のCPUに維持されて、大きな負荷をシミュレートします。

あなたは(日報を見つけるためにブラウズ)このサイトで公にここでの結果を見ることができます。 https://msit.powerbi.com/view?r=eyJrIjoiYTZjMTk3YjEtMzQ3Yi00NTI5LTg5ZDItNmUyMGRlOTkwMGRlIiwidCI6IjcyZjk4OGJmLTg2ZjEtNDFhZi05MWFiLTJkN2NkMDExZGI0NyIsImMiOjV9&pageName=ReportSectioneeff188c61c9c6e3a798

これにより、過去にいくつかの問題を修正し、現在システムに根本的なリークがないことを確信できました。 しかし、出荷するすべてのコンポーネントを使用することにはほど遠いため、特定する必要のある問題がある可能性があります。 問題を再現するダンプとアプリケーションを提供することが、私たちを助けることができる主な方法です。

@sebastienrosアップデートありがとうございます。 私たちの場合、問題は新しい「貪欲なメモリ割り当て」の懸念に関するものであり、元々はメモリリークと誤解していたことを私は知っています。 現在問題があるかどうかさえわかりません。新しい最適化ヒューリスティックがはるかに積極的である可能性があります。 わかりません...しかし、あなたはこのスレッドを実際に評価し、人々が見ているもの/誤解しているものについてのいくつかの統合された説明/要約を考え出すことで正しい軌道に乗っていると思います。 幸運を!

すべての個別のレポートは分離されており、個別のフォローアップが行われ、すでに解決されている場合は閉じられます。 ループにとどまるためにこれらを購読してください。

並行して、すべての推奨事項、既知のメモリの問題(LOB、HttpClientなど)、およびこれらの問題を分析および報告する方法をリストしたドキュメントを作成します。

これは私からの大きな+1です。 ここでの最大の問題の1つは、情報を収集し、問題が何であるかを判断するのに役立つことがどれほど難しいかということだと思います。 (i)収集、(ii)自己診断の試行、(iii)MSチームにとって効率的な方法でのダンプ/検出結果の投稿の両方に、いくつかの指示に従うことができる優れたドキュメントがあると、両方に役立ちます。柵の側面。

私たち(開発者)がより適切に診断および/または情報を提供できるようになれば、これはすべての人にとって双方にメリットがあります。

@sebastienrosを聞いてくれてありがとう-とても感謝しています、メイト!

下の写真の状況についてどう思いますか?

同じプラン内で4つのWebAppを実行します。 最初はB1で、S2にスケールアップされ、空腹のwebapp csprojに設定するまで、メモリは増え続けました。

<ServerGarbageCollection>false</ServerGarbageCollection>

また、ApplicationInsightsを無効にします

  1. 上記の設定でメモリを制御できるので、メモリリークはないと思います。 正しい?
  2. 提示された動作は正常ですか?

memory eaten up

ここでは@alexiordanと同じ状況で、.netコア2.1コンソールがあり、Microsoft / dotnet :2.1- runtimeASbaseからKubeでホストされているいくつかのIHostedServicesを実行していました。 HealthChecksを有効にしたかったので、HealthChecksミドルウェアだけでasp.netを追加し、ベースイメージをmicrosoft / dotnet:2.1-aspnetcore-runtimeに変更しました。 結果はOOMでした。 追加することでメモリ割り当てを安定させることができましたfalse csprojで。

私たちの分析によると、asp.netアプリでは、GCの収集頻度が低く、ファイナライザーキューのトラバース頻度も低くなっています。

また、パイプラインに以下を追加して、GCにファイナライザーキューを収集してトラバースさせる場合、

System.GC.Collect();
System.GC.WaitForPendingFinalizers();
System.GC.Collect();

メモリ割り当ては安定したままでした。

下の写真の状況についてどう思いますか?

同じプラン内で4つのWebAppを実行します。 最初はB1で、S2にスケールアップされ、空腹のwebapp csprojに設定するまで、メモリは増え続けました。

<ServerGarbageCollection>false</ServerGarbageCollection>

また、ApplicationInsightsを無効にします

  1. 上記の設定でメモリを制御できるので、メモリリークはないと思います。 正しい?
  2. 提示された動作は正常ですか?

memory eaten up

ねえ@alexiordan

AI(ネットコア2.1上のWebアプリ)を使用している場合にも、非常によく似たメモリプロファイルが表示されますが、これを解決するためにさらに進んだことはありますか? もちろん、アプリにAIを残したいのです。

リクエストごとに使用量が増えるのはおかしいですが、上記をfalseに設定すると、停止するように見えますか? 本当はそれを可能にする価値だと思うので奇妙ですが、それは逆のようです...

このスレッドで説明されている問題についての記事を書くつもりであると発表した直後に、私は実際にそれを行ったことに言及するのを忘れました。 あなたはここでそれを見ることができます: https ://github.com/sebastienros/memoryleak

チャート上のパターンをライブでレンダリングする小さなアプリケーションが付属しています。

しかし、上記をfalseに設定すると、私にとってはそれを止めるように見えますか? 本当はそれを可能にする価値だと思うので奇妙ですが、それは逆のようです...

クライアントのガベージコレクション(多くのアプリとのメモリ共有とメモリの空き容量の維持に最適化)は、サーバーのガベージコレクション(スループットと同時実行性に最適化)よりも積極的です。

SGCをfalseに設定すると、私のasp.netコアAPIは150MBから48MBに低下し、その後のリクエストごとに拡張されませんでした。 それで、実際には、これは今のところ、本番環境に最適な設定ですか?

@kgrosvenor実際には、状況によって異なります。 優れた@sebastienrosの記事からの引用:

一般的なWebサーバー環境では、CPUリソースはメモリよりも重要であるため、サーバーGCを使用する方が適しています。 ただし、一部のサーバーシナリオは、ワークステーションGCにより適している場合があります。たとえば、メモリが不足するリソースになる複数のWebアプリケーションをホストする高密度の場合です。

非常に便利なことをありがとう、私は心に留めておきます-これ以上の更新についてはこのスレッドをフォローします、それは私が絶対にasp.netコアを愛していると言われています:)

また、.netコア2.1コンソールアプリでこれに苦しんでいます。 一定のメモリの増加。 Dockerコンテナーを低い最大値に設定したため、Dockerコンテナーにヒットして再起動します。これは正常に機能していますが、醜いです。

こちら側のニュースはありますか? ASP.NetCorev2.1でも同じ動作があります。 コミットhttps://github.com/aspnet/AspNetCore/commit/659fa967a1900653f7a82f02624c7c7995a3b786で確認できることから、v3.0で修正される予定のメモリ管理の問題があったようです。

@ flo8 2.2にアップグレードして、動作を確認しましたか? https://dotnet.microsoft.com/download

最新の2.2を実行すると、この問題も発生します。100万intのリストを作成し、emptyResult()を返すだけで、メモリがなくなるまで、リクエストごとにヒープが数百MB増加します。 ServerGarbageCollectionをfalseに設定すると、正しい修正ではないように見えますが、修復されました...

@ dre99gsx簡単に再現できるようですが、プロジェクトと手順を共有して、同じことをローカルで実行できるようにしていただけませんか。

この場合、LOBを埋める必要がありますが、gen2で収集する必要があります。 また、OS、メモリ、負荷など、これを再現できる環境を教えてください。

不可解な応答でごめんなさい。 結構簡単:
(Windows 7 64ビット、16GB RAM、httpリクエスト用のGoogle Chrome、VS2017コミュニティ)-これらのスレッドにコードを追加することにまだ慣れています、外観はご容赦ください)

  • 新しい.NETCore2.2Webアプリを起動します
  • スコープ(特別なことは何もありません)のサービスクラスをコントローラーコンストラクターに注入します
  • コントローラのIndex()アクションで、このサービスクラスのメソッドを呼び出させます
  • 次の1つのプロパティを使用してモデルクラス(DumbClass)を作成します。publicint ID {get; セットする;}
  • サービスクラスメソッドで、リストをインスタンス化し、データを入力します。
    varlst=新しいリスト();
    for(i = 0; i <10000000; i ++)<---注:1,000万回の反復
    {{
    lst.add(new DumbClass(){ID = i});
    }
  • メソッドから戻る場合は、何も返す必要はありませんが、そのリストを返すこともできます...
  • index()は新しいEmptyResult();を返します。

ここで、8秒ごとにアクションを呼び出し、プロファイラーのメモリが増加するのを確認します。 私のシステムでは、これは私がプライベートバイトで見るものです:

アプリケーションの開始:155MB
最初のhttpgetリクエスト:809MB
2番目:1.2GB
3番目:1.4GB
4番目:1.8GB
5番目:2.1GB ... 2.3GB .. 2.6GB .. ..

現在、ある時点でGCが開始されたように見えますが、この例では3GBを下回ることはありません。 前述のように、ServerGCをfalseにすると、1GBを超えることはありませんが、それでも1GBで上昇し、ホバリングします。

それが役立つかどうか、そしてあなたがそれを再現できるかどうか私に知らせてください。 ああ、私はあなたのgithubの投稿を読みました:「ASP.NETCoreのメモリ管理とパターン」、素晴らしい記事、貢献してくれてありがとう!

@ dre99gsx👋

私はまだこれらのスレッドにコードを追加することに慣れています、外観を許してください)

問題はまったくありません:)質問:サンプルアプリケーション全体をGitHub (無料のリポジトリ)または同様の場所に実際に配置できますか? これは、他の人があなたが遊んでいる正確なサンプルアプリ/リポジトリ全体をすばやく複製/ダウンロードするための最も簡単な方法です。

また、 TaskManagerを使用したメモリ使用量のスクリーンショットが役立ちます(Windowsの場合-または* nix ..の同等のtopコマンド??)

これまでのところ大変な努力です!

/ meは、このスレッドを真剣に静かに見ていることに戻ります。

https://github.com/sebastienros/memoryleakのスレッドで説明されているすべての症状のデモと説明を確認できます。

また、これらの問題はそれぞれ個別に処理されており、ドットネットコアのバグであることが証明されているものはありませんが、予想される動作です。

@ dre99gsx最近のコメントに戻りますが、このスレッドとは別の問題を提出することをお勧めします。 私の電話にいると、それが「これ」だとは気づかなかった;)。 あなたの最初のコメントからあなたは述べます

メモリがなくなるまで

したがって、OutOfMemory例外が発生することが予想されます。そのため、再現を要求しました。 しかし、あなたの次のコメントであなたは述べます:

さて、ある時点で、GCが開始されたように見えますが、この例では3GBを下回ることはありません。

したがって、メモリの問題はありません。 これは、多くのコアと多くの使用可能なメモリを備えたマシンでよく見られます。 GCは管理対象ヒープを解放しますが、コミットを解除する理由がないため(使用可能なメモリが大量にあるため)、メモリは引き続きコミットされます。 これは.NETの標準的な動作であり、私が指摘した記事でデモを行います。 これも読むことができます: https ://blogs.msdn.microsoft.com/maoni/2018/11/16/running-with-server-gc-in-a-small-container-scenario-part-0/

ランタイムチームは現在、コンテナーで実行されている.NETアプリケーションを制約する方法に取り組んでいることを知っています。そのため、一部のマイクロサービスシナリオを解決するために、3.0を対象として、それほど多くのメモリを使用しません。

また、自分でわかったように、アプリケーションがサーバーで使用可能なすべてのメモリを使用できない場合は、ワークステーションのGCモードを使用する必要があります。

正解です。「メモリが不足しています」と言ったときは、Windowsプライベートワーキングセット(タスクマネージャー)を介して他のアプリケーションで使用できるメモリがないことを視覚的に確認することに基づいています。 「メモリ不足の例外」ではありません。

あなたは何を知っている、あなたは正しい。 これはますます期待される動作のように見えます。使用可能なメモリが非常に多い場合、他の誰もそれを必要としないのに、なぜリソースを使ってそれを解放するのですか? わかった。 GCがメモリを解放するのに十分スマートで、他のアプリケーションが制限されない限り、私はそれをそのままにして、それを実行させます。 再度、感謝します!

Asp.net Core 2.2でアプリケーションを開発しましたが、メモリの解放に関連する同じ問題に直面しています。
呼び出しごとに、解放されるたびに40〜50Mbの範囲でメモリが増加します。

上記のタグServerGarbageCollection>falseも追加しました
50ユーザーでも同じ問題に直面しており、インプロセスモードで約2GBのRAMを使用しています(w3wp iisワーカープロセス)

助けてください。

助けてください !! ankitmori14と同じ問題

@ ankitmori14 、@ ikourfaln - https: //github.com/aspnet/AspNetCore/issues/1976#issuecomment -449675298で@sebastienrosのコメントを読み、それでもメモリの問題があると思われる場合は、新しい問題を提出してください問題を再現するための詳細な手順に加えて、動作に関するその他の情報とトレースが含まれています。 アプリ/プロセスに実際にエラーが発生していない限り、バグが発生する可能性は低い(ただし不可能ではない)ことを忘れないでください。 デフォルトの「サーバー」ガベージコレクターは、可能な限り最小限のメモリを使用しようとはしません。 むしろ、メモリが実際に不足しているときなど、必要なときに起動します。 したがって、小さなアプリでも2GBのメモリを使用する可能性がありますが、4GBの空き容量があるため、問題はありません。

やあ、

この問題が発生しています: https ://stackoverflow.com/questions/53868561/dotnet-core-2-1-hoarding-memory-in-linux

基本的に、メモリは、設定された512Mbの制限に達したために、Kubernetesがメモリを強制終了するまで、プロセスの数日間で増大します。 おかしなことに、メモリダンプを取得しているときに、プロセスを再起動するなどせずに、メモリが大幅にダウンしました。 メモリダンプを調べると、ルートのないオブジェクトがたくさん見つかりました。

昨日、並行GC(つまり、バックグラウンドGC)も無効にしました。今は改善されているようですが、確認するには少なくとも1週間待つ必要があります。

<PropertyGroup>
  <ServerGarbageCollection>false</ServerGarbageCollection>
  <ConcurrentGarbageCollection>false</ConcurrentGarbageCollection>
</PropertyGroup>

@vtortolaの質問、アプリケーションに512Mbの制限を構成したとき、処理したい同時リクエストの数を知っていましたか、またはアプリがフォールオーバーする前に処理できる同時リクエストの数をテストしましたか?

いくつかの予備テストと大まかなテストを行い、512Mbを使用してポッドごとに500の同時WebSocketを処理できることを確認しました。 2つのポッドと1000の同時接続で何時間も実行し、メモリは150Mb未満でした。 2つのポッドを備えたデプロイ済みアプリケーションには、いつでも150〜300の同時接続があり、メモリは最初の数日間で100Mb未満から、約2週間で512Mbに達するまで変化します。 接続数と使用メモリの間に相関関係はないようです。 接続の70%以上が10分間続きます。

100MBと512MBのメモリダンプを共有して、どのインスタンスがまだ生きているかを確認できますか?

ダンプにはCookie、トークン、および多くのプライベートデータが含まれているため、ダンプを共有できません。

それでは、ローカルで比較できますか? どのオブジェクトが最も多くのメモリを消費するか、そしてそれらの数が負荷と相関しないかどうかに関して。 300の接続がある場合のように、3Kの接続オブジェクトがあってはなりません。

残念ながら、 <ConcurrentGarbageCollection>false</ConcurrentGarbageCollection>を設定するテストは役に立たず、プロセスはまだメモリを蓄えています。

プロセスのLinuxダンプがあり、それを分析する必要がある唯一のツールはlldbであり、この問題については非常に初心者です。

ベルが鳴った場合のデータは次のとおりです。

(lldb) eeheap -gc
Number of GC Heaps: 1
generation 0 starts at 0x00007F8481C8D0B0
generation 1 starts at 0x00007F8481C7E820
generation 2 starts at 0x00007F852A1D7000
ephemeral segment allocation context: none
         segment             begin         allocated              size
00007F852A1D6000  00007F852A1D7000  00007F853A1D5E90  0xfffee90(268430992)
00007F84807D0000  00007F84807D1000  00007F8482278000  0x1aa7000(27947008)
Large object heap starts at 0x00007F853A1D7000
         segment             begin         allocated              size
00007F853A1D6000  00007F853A1D7000  00007F853A7C60F8  0x5ef0f8(6222072)
Total Size:              Size: 0x12094f88 (302600072) bytes.
------------------------------
GC Heap Size:            Size: 0x12094f88 (302600072) bytes.

そしてdumpheap -statの結果: https ://pastebin.com/ERN7LZ0n

Grafanaがメモリの状態をどのように報告していたかはhttps://stackoverflow.com/questions/53868561/dotnet-core-2-1-hoarding-memory-in-linuxで確認できます。

dotnetコアには、WebSocketを使用していませんが、問題なく動作する別のサービスがあります。

@vtortolaは、新しい問題を作成していただけませんか。この問題をフォークしません。 WebSocketを使用しているという事実は、WebSocketをユニークなものにしていると思います。少なくとも、あなたのように動作し、長期間にわたってストレスを与えるサンプルアプリを作成する必要があります。 クライアントがWebSocketで何をしているのか、WebSocketにどのように接続しているのか、そしてどのくらいの期間かを説明できますか? このようなアプリをセットアップして数日かけて実行し、メモリが増えているのを確認したらメモリダンプを取得できます。

また、GCがポッドの制限に近づいていることを警告されないように、GCとKubernetesの間で競合が発生している可能性もあります。

@richlanderは同様の問題に取り組んでいます。 このケース(最後の6つのコメントのみを読む)は、あなたが取り組んでいることに関連している可能性がありますか?

それが何か違いを生むなら、私は同じ(または非常に似た)問題を抱えています。 Dockerで実行されている.netコア2.1および2.2コンソールアプリが12個以上あります。各コンテナーには512MBのメモリ制限があり、Webソケット(クライアント)も使用しています。アプリは約3日ごとにコンテナーのメモリ制限に達します。 その後、コンテナはシャットダウンして再起動します。

すべてが認証されたサービスを使用しているため、私が持っているものを提供することはできませんが、テストサイトを使用して問題を再現するものをまとめることはできるかもしれません。

メモリ制限を設定するためにどのパラメータを使用しますか? ちょうど--memoryまたは--memory-swap

テストすると、16MiBのような超低制限であっても、設定した制限を超えることはなく、非常によく考慮されていることがわかりますが、ディスク上で狂ったようにスワップします。 そして、dbクエリ(EF)とRazorビューのレンダリングを行うアプリでテストしています。

@sebastienros絶対に、私はhttps://github.com/aspnet/AspNetCore/issues/6803を作成しました

さらに情報が必要な場合はお知らせください。

現在、メモリの問題が発生しています。

本番環境で1時間経過すると、すべてのメモリがw3wp.exeプロセス(.NET Core InProcessを実行)によって使用されます。 GCをWorkstationに変更しても、うまくいきませんでした。

メモリダンプを分析した後、私はこの同様の問題、 https://github.com/aspnet/AspNetCore/issues/6102を見つけました。

最新の.NETCoreランタイム(現在は2.2.3)にアップグレードした後、本番環境でテストすることを望んでいます。 どうなるかお知らせします。

私はメモリの使用に関して同様の問題を抱えています。 Linuxコンテナーに制限を設定すると、OOMが速くなります。 VisualStudioの基本的なテンプレートを使用しても発生します。 私が見つけた1つのこと-コア2.1と2.2が影響を受けます。 Core 2.0はそうではありませんが、EOLです:(

上記を参照

ランタイムチームは現在、コンテナーで実行されている.NETアプリケーションを制約する方法に取り組んでいることを知っています。そのため、一部のマイクロサービスシナリオを解決するために、3.0を対象として、それほど多くのメモリを使用しません。

また、自分でわかったように、アプリケーションがサーバーで使用可能なすべてのメモリを使用できない場合は、ワークステーションのGCモードを使用する必要があります。

悲しいことに、ワークステーションモードはまったく役に立ちません-悲しいことに、私は3.0プレビューまたは同様のものの1つを試す立場にありません。

@PrefabPandaは、 System.Runtime.GCSettings.IsServerGCfalseであることを確認して、実際にワークステーションGCモードで実行していることを確認します。

次に、これは本物のメモリリークである可能性があります。 別の問題を開くのがおそらく最善のステップです。

@ wanton7-ありがとう、私は再確認しました、そしてそれは間違いなく設定されています。

@DAllanCarr-します

メモリリークではないとほぼ確信しています。 Docker設定が正しく適用されない可能性があり、制限に達する前にGCが起動しない可能性があります。 この意味で、3.0では修正が導入されていることを私は知っています。

@richlanderこの問題は、2.2では機能しないことがわかっている問題のように見えますか?

@PrefabPanda使用している正確なDockerバージョンとDocker作成ファイルを共有していただけませんか? 再現しようとしていますが、dockerとdocker-composeバージョンの間で、この問題をローカルで再現するのに苦労しています。

@ sebastienros@richlander-私に戻ってきてくれてありがとう。 ほんとうにありがとう。

私のDockerバージョン:

Dockerデスクトップコミュニティ
バージョン2.0.0.2(30215)

エンジン:18.09.1
作成:1.23.2

添付のテストプロジェクト全体を参照してください。
WebApplication1.zip

curlrequests.zipをテストします

念のため、私のDockerfile:

FROM mcr.microsoft.com/dotnet/core/ aspnet: 2.2ASベース
WORKDIR / app
EXPOSE 80
EXPOSE 443

FROM mcr.microsoft.com/dotnet/core/ sdk: 2.2ASビルド
WORKDIR / src
COPY ["WebApplication1 / WebApplication1.csproj"、 "WebApplication1 /"]
dotnet restore "WebApplication1/WebApplication1.csproj"を実行します
コピー 。 。
WORKDIR "/ src / WebApplication1"
dotnet build"WebApplication1.csproj"-cリリース-o/appを実行します

FROMビルドAS公開
dotnet publish"WebApplication1.csproj"-cリリース-o/appを実行します

FROMベースASファイナル
WORKDIR / app
COPY --from = publish/app。
ENTRYPOINT ["dotnet"、 "WebApplication1.dll"]

docker-compose.yml:

バージョン:「2.4」

サービス:
webapplication1:
画像:$ {DOCKER_REGISTRY-} webapplication1
mem_reservation:128m
mem_limit:256m
memswap_limit:256m
CPU:1
建てる:
環境: 。
dockerfile:WebApplication1 / Dockerfile

docker-compose-override.yml:

バージョン:「2.4」

サービス:
webapplication1:
環境:
--ASPNETCORE_ENVIRONMENT=開発
-ASPNETCORE_URLS = https:// +:443; http:// +:80
-ASPNETCORE_HTTPS_PORT = 44329
--DOTNET_RUNNING_IN_CONTAINER = true
--DOTNET_SYSTEM_GLOBALIZATION_INVARIANT = true
--ASPNETCORE_preventHostingStartup = true
ポート:
-「50996:80」
-「44329:443」
ボリューム:
-$ {APPDATA} /ASP.NET/Https:/root/.aspnet/ https:ro
-$ {APPDATA} / Microsoft / UserSecrets:/root/.microsoft/us ersecrets:ro

@sebastienros -GCが調べるために別の環境変数をコンテナに入れる方法があったとしても、それは私にとっては問題なく機能します。

明示的に呼び出してみましたが、役に立ちません。コードで呼び出しても、コンテナ/マシンのメモリサイズが間違っていると思います。

@PrefabPanda 「明示的に呼んでみました」とおっしゃったとき、正確にはどういう意味か詳しく教えていただけますか? GCは、コンテナのメモリ制限が指定されている場合、それが自然にトリガーされたか誘導されたかに関係なく、正しいコンテナメモリ制限を認識します。 GC.Collect()を呼び出すと、完全なブロッキングコレクションが実行されます。 また、GC.Collect(2、GCCollectionMode.Default、true、true)を実行すると、コンテナーの制限などに関係なく、ヒープが可能な限り最小のサイズであることが返されるときに、完全に圧縮されたGCが実行されます。

こんにちは@Maoni0-私はGC.Collect(2、GCCollectionMode.Default、true、true)を試しました

256MBは2.2には小さすぎるという別のコメントを見たばかりですが、3.0では「修正」される可能性があります。 もう少し実験する必要があるようです...

GC.Collect(2、GCCollectionMode.Default、true、true)を試しても、メモリが期待どおりにダウンしなかった場合は、真のメモリリークがあることを意味します。 ご使用の環境で使用可能なツールの量がわかりません。 sosコマンドを実行できますか? もしそうなら、あなたはいつでもあなたの誘発されたGCの後にヒープに残っているものを見ることができます

ありがとう@Maoni0-私はVisualStudioでテンプレートを使用していることを覚えておいてください-私が添付したこのテストプロジェクトには、文字通り私自身のコードはありません。 他にもフィードバックがありますので、ご連絡いたします。 どうもありがとう。

@ Maoni0-上限を設定してみましたが、違いはありません。 3.0プレビューを試してみる必要があるようです

この問題は非常に古いものであり、すべてのケースが別々の問題で扱われているため、この問題に関するコメントをロックしたいと思います。 https://github.com/aspnet/AspNetCore/issues/10200にコメントしていると思って、誤ってこれにコメントしました

ありがとう

このページは役に立ちましたか?
0 / 5 - 0 評価