Microsoftは5月21日(米国時間)、「Memory leak from improper usage of Microsoft.Extensions.Configuration APIs in .NET on Windows | Microsoft Community Hub」において、不適切なAPIの使用がメモリ不足(OOM: Out Of Memory)を発生させるとしてその一例を解説した。

この例で示したコードは頻繁に利用されており、すべての.NETアプリで発生する可能性があるとして注意を呼びかけている。

  • Memory leak from improper usage of Microsoft.Extensions.Configuration APIs in .NET on Windows|Microsoft Community Hub

    Memory leak from improper usage of Microsoft.Extensions.Configuration APIs in .NET on Windows | Microsoft Community Hub

増え続ける固定されたメモリ領域

多くの場合、メモリ不足は無限にメモリを消費するプログラムのバグが原因で引き起こされる。今回の例もプログラムのバグを原因とするが、公式のサンプルコードをコピーしただけで発生するという。

今回の例をより正確に把握するには、.NETのガベージコレクション(GC: Garbage Collection)の仕組みを理解しておく必要がある。ここでは公式ドキュメントの「ガベージ コレクションの基礎 - .NET | Microsoft Learn」に説明を譲り割愛する。

.NETのガベージコレクションとは

.NETのガベージコレクションにはジェネレーションという概念があり、GEN0からGEN2までの分割された3つの領域が存在する。新しいオブジェクトはGEN0に割り当てられ、有効期間が長いと判断されるとGEN1またはGEN2に昇格する仕組みだ。

問題はGEN2に存在する固定(Pinned)されたオブジェクトで発生する。固定されたオブジェクトはメモリーアドレスの変更ができないため、再配置することができない。GEN2に固定されたオブジェクトが複数存在すると、その間にあるオブジェクトが解放されても後続のオブジェクトを移動して埋めることができず、空き領域が残ることになる。

この空き領域を新しいオブジェクトで消費したいところだが、新しいオブジェクトは必ずGEN0に割り当てる必要があり、GEN2の空き領域を直接消費することはできない。こうして徐々に使用できない空き領域が増加し、メモリ不足に陥る。

サンプルコードに問題あり

固定されたオブジェクトに原因があるとわかっているのであれば使用しなければよい。しかしながら、Microsoftは頻繁に利用される次のコードを例に示し、固定されたオブジェクトを明示的に使用しなくてもメモリー不足に陥る可能性があると指摘している。

  • OOMを発生させる問題のコード - 引用:Microsoft

    OOMを発生させる問題のコード 引用:Microsoft

このコードの問題点は「reloadOnChange: true(デフォルトはfalse)」にあるという。同社によると、この値はASP.NETが自動的に使用しないカスタム構成ファイルを使用する場合に、起動時に1度だけ使用することを想定しているとされる。

公式ドキュメントの「Configuration in ASP.NET Core | Microsoft Learn」や「Configuration providers - .NET | Microsoft Learn」には、よく似たサンプルコードがある。つまり、一部のユーザーがコードを理解しないまま使用し、それが広まったものと推測されている。

解決策

Microsoftは安易な解決を選択する前に、複数の構成ファイルについて十分に調査し、適切な取り扱い方法を設計する必要があるとしている。それでもカスタム構成ファイルを監視する必要がある場合、プログラムの起動時に1度だけ追加し、それ以降は取得メソッドのみを使用するように推奨している(参考:「Configuration in ASP.NET Core | Microsoft Learn」、「Configuration - .NET | Microsoft Learn」)。

この問題はreloadOnChangeをfalseにすることでも解決できるが、同社は非効率的で動作が遅くなるとして推奨していない。なお、この問題は.NET 7以降で発生しやすく、Windows環境のみ影響を受けるという。

公式ドキュメントに記載されたサンプルコードは信頼性が高く、そのまま利用したい気持ちに駆られる。しかしながら、その動作を正確に把握して利用しないと、予想外の落とし穴に嵌る可能性がある。Microsoftは同様の問題が数年前から発生しているとして、注意を呼びかけている。