Skip to content

投稿

.Net Coreにおけるガベージコレクションのタイプ

2019年9月2日 • 8分で読める

.Net Coreにおけるガベージコレクションのタイプ

現代の言語におけるメモリ管理は、しばしば後回しにされがちです。実際のところ、私たちはメモリについてほとんど考えることなくソフトウェアを書いています。これは私たちにとって有益ですが、常に例外があります…

カリフォルニア州では、地方教育機関(LEA)に対する広範囲な財務報告要件があります。LEAは郡、学区、チャータースクール、または単一の学校である場合があります。ほとんどのLEAは独自の財務報告書を作成しており、通常はExcelを中心としているため、各報告書が異なることは驚くことではありません。この問題を解決するため、カリフォルニア州教育委員会は財務報告書を生成するソフトウェアの開発を委託しました。

私はその開発チームの一員でした。

最初に確認したのはテストログでした。Ed-Proのログは高いメモリ使用量を示しており、メモリリークがあるのではないかと考えました。エンジニアは、Ed-Proの計算が大量の短期間メモリを使用していることを観察しました。メモリが迅速にクリーンアップされなければ、メモリリークのように見える可能性があります。

Ed-ProはMicrosoftのマルチプラットフォームフレームワークである.Net Core上に構築されています。.Net Coreでは、メモリは3つのタグに分けられます:短期間(Gen0)、中期間(Gen1)、長期間(Gen2)です。Gen0は迅速にスコープから外れる短期間データ用、Gen1は少し長く残る中期間メモリ用で、これも最終的にはスコープから外れ、Gen2はアプリケーションの生存期間中存在する可能性のある長期間メモリです。Gen0メモリは常に回収され、Gen1はGen0より頻度が低く回収され、Gen2はGen1よりもさらに頻度が低く回収されます。

Ed-Proのメモリ使用量を理解する唯一の確実な方法は、プロファイリングすることでした。以下はJetBrainsのdotMemoryを使用したスクリーンショットです。

予想通り、大量のGen0メモリ(青色)を発見しました。あまりにも多く、ガベージコレクションが追いつけないように見えました。大量のメモリを補償する戦略により、ガベージコレクションはメモリ空間の増加(アプリケーション使用のためのメモリ追加)とクリーンアップの間で振動していました。クリーンアップサイクル中、アプリケーションは応答しなくなります。

最初は困惑しました。GCの目的はメモリを整理することではないのでしょうか?.Netにおけるガベージコレクションの動作を理解するのに、2つの記事が重要でした:Mark Vinczeの記事「Troubleshooting high memory usage with ASP.Net Core on Kubernetes」とMicrosoftによる「Fundamentals of Garbage Collection」です。どちらも素晴らしい読み物で、Ed-Proのメモリ使用量に明確さをもたらしました。

学んだことの要約は以下の通りです。.Netには2つのタイプのガベージコレクションがあります:サーバーガベージコレクションとワークステーションガベージコレクションです。

サーバーガベージコレクションはいくつかの仮定をします:第一に、十分なメモリが利用可能であること、第二に、プロセッサがマルチコアで高速であることです。どちらも真実である可能性がありますが、私たちは仮想マシンとDockerの世界に住んでおり、両方の仮定が偽である可能性が高いです。

サーバーガベージコレクションはメモリの蓄積を許可し、ある時点で2つのうちの1つを行います:メモリ空間を増加させてメモリの成長を許可するか、孤立したメモリを解放するかです。メモリを解放することを選択すると、ガベージコレクションは高優先度スレッドでプロセスを開始します。高優先度スレッドはアプリケーションよりも高い優先度を持ちます。マシンが高速であれば、クリーンアップは気づかれないはずです。しかし、そうでなければ、クリーンアップが完了するまでアプリケーションが停止します。

ワークステーションガベージコレクションは異なる動作をします。アプリケーションと同じ優先度のスレッドでメモリを回収し続けます。これは、アプリケーションとリソースを競合することを意味し、アプリケーションの速度低下を引き起こす可能性があります。利点は、特に大量のGen0を使用する場合、アプリケーションのメモリ使用量を非常に低く保つことができることです。

デフォルトでは、.Net Coreがサーバーを検出すると、サーバーガベージコレクションタイプを実行します。これが私たちのアプリケーションの場合でした。ワークステーションガベージコレクションタイプを実行するには、プロジェクトファイルに以下のスニペットを追加します:

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

Ed-Proにこの設定変更を行い、dotMemoryを使用して、ワークステーションガベージコレクションを有効にしたEd-Proのメモリをプロファイリングし、前回のテストと同じ画面を読み込みました。結果は以下の通りです:

メモリ使用量は大幅に減少しました。Gen0の割り当ては事実上存在しません。グラフの違いを超えて、サーバーガベージコレクションのメモリ使用量は1ギガバイトに達しましたが、ワークステーションガベージコレクションは約200メガバイトでピークに達しました。

すべてのアプリケーションは異なります。私たちのアプリケーションは大量の一時的なデータを使用し、したがって大量のGen0メモリを使用します。あなたのアプリケーションはGen1やGen2などの長期間メモリを活用する可能性があり、その場合サーバーガベージコレクションが非常に理にかなっています。私のアドバイスは、メモリがどのように使用されているかを理解するために、異なる条件下でメモリをプロファイリングし、その後あなたのアプリケーションにとって最適なモードを決定することです。

著者:Chuck Conwayはソフトウェアエンジニアリングと生成AIを専門としています。ソーシャルメディアで彼とつながりましょう:X (@chuckconway) または YouTube をご覧ください。

↑ トップに戻る

こちらもおすすめ