C# メモリ リーク

王林
王林オリジナル
2024-09-03 15:21:56419ブラウズ

メモリ リークは、プログラムまたはアプリケーションがシステムのプライマリ メモリを長期間にわたって使用するときに発生する状況です。プログラムが実行プロセスを完了した後でも、実行中に占有されていたメモリを解放しない場合、この割り当てられたメモリ領域によってシステムのパフォーマンスが低下し、応答しなくなる可能性があります。このトピックでは、C# のメモリ リークについて学習します。

未使用の割り当てられたメモリを解放するのはガベージ コレクタの責任ですが、アプリケーションの存続期間を通じてスコープ外に出ることのない変数から未使用のオブジェクトを参照することがあるため、依然としてメモリ リークの問題が発生します。

構文

C# ではメモリ リークを回避する方法がたくさんあります。内部的に Dispose() メソッドを呼び出す「using」ステートメントを使用すると、アンマネージ リソースを操作する際のメモリ リークを回避できます。 「using」ステートメントの構文は次のとおりです:

using(var  objectName = new AnyDisposableType)
{
//user code
}

上記のステートメントでは、「var」はあらゆるタイプのデータを格納するために使用されるキーワードであり、コンパイラーはコンパイル時にこのデータタイプを認識できます。 「objectName」は、オブジェクトのユーザー定義の名前です。 「new」はオブジェクトの初期化に使用されるキーワードで、「AnyDisposableType」は StreamReader、BinaryReader、SqlConnection などのクラスで、そのオブジェクトは「using」ステートメントを使用して破棄できます。

C# でのメモリ リークはどのように機能しますか?

.NET アプリケーションの場合、未使用のメモリを処分するガベージ コレクターがありますが、それでもメモリ リークの問題が発生します。これはガベージ コレクターが適切に動作しないことを意味するのではなく、プログラマの無知が原因で発生します。

アプリケーションのメモリ リークを非常に長期間無視するとします。その場合、アプリケーションのメモリ消費量が増加し、アプリケーションのパフォーマンスが低下し、徐々にアプリケーションが破壊され、OutOfMemoryException が発生する可能性があります。

C# でのメモリ リークの主な原因は 2 つあります。

  • 最初の原因は、不要になった未使用のオブジェクトが、アプリケーションの存続期間全体にわたって有効範囲を持つ変数によって依然として参照されていることです。このオブジェクトには参照があるため、ガベージ コレクターによって破棄されず、メモリ内に永久に残り、メモリ リークの原因となる可能性があります。この状況の例としては、登録したものの登録が解除されないイベントが挙げられます。
  • 2 番目の原因は、アンマネージド リソースにメモリを割り当て、使用後にメモリを解放しないことです。管理対象リソースと同様、アンマネージド リソースは自動的にガベージ コレクションを行うことができません。したがって、使用後にそのメモリを解放するのはプログラマの責任です。

C# でメモリ リークが発生する理由は次のとおりです。

  • イベントをサブスクライブすると、イベントを発行するクラスは、イベントをサブスクライブするクラスへの参照を保持します。このため、ガベージ コレクターはイベントをサブスクライブしたクラスのオブジェクトを破棄せず、同時にプログラマがそのイベントをサブスクライブ解除しないとメモリ リークが発生します。
  • 匿名メソッドでクラス メンバーをキャプチャすると、メモリ リークが発生する可能性があります。
  • 静的クラスとそれに関連付けられた静的変数、およびこれらの静的変数によって参照されるものはガベージ コレクションできず、メモリ リークが発生する可能性があります。
  • キャッシュ機能を無期限に使用すると、メモリ リークが発生する可能性があります。
  • アプリケーション内にタスクがなく、オブジェクトを参照する無限に実行されるスレッドがある場合、メモリ リークが発生する可能性があります。
  • ガベージ コレクターはアンマネージド リソースを管理しません。したがって、アンマネージ リソースを使用後に破棄しないと、メモリ リークが発生する可能性があります。

C# メモリ リークの例

さまざまな例を以下に示します:

例 #1

この例は、スレッド自体が終了するのを待機しているため、メモリ リークの原因となる可能性があることを示しています。

コード:

using System;
using System.Threading;
namespace ConsoleApp4
{
public class Program
{
public static void Main()
{
while (true)
{
Console.WriteLine("Press enter key to start new thread");
Console.ReadLine();
Thread thread = new Thread(new ThreadStart(StartThread));
thread.Start();
}
}
public static void StartThread()
{
Console.WriteLine("Thread " +
Thread.CurrentThread.ManagedThreadId + " started");
//Wait until current thread terminates
Thread.CurrentThread.Join();
}
}
}

出力:

C# メモリ リーク

上記のプログラムで「Enter」を押すたびに、メモリ使用量が増加します。

例 #2

メモリ リークを回避するための「using」ステートメントを使用したアンマネージ リソースの使用を示す例。

コード:

using System;
using System.IO;
namespace ConsoleApp4
{
public class Program
{
public static void Main()
{
string filePath = @"E:\Content\memoryLeak.txt";
string content = string.Empty;
try
{
//writing file using StreamWriter
//making use of 'using' statement to dispose object after using it
using (StreamWriter writer = new StreamWriter(filePath))
{
writer.WriteLine("Learning C# programming");
}
//reading file using StreamReader
using (StreamReader streamReader = new StreamReader(filePath))
{
content = streamReader.ReadToEnd();
}
}
catch (Exception exception)
{
Console.WriteLine(exception.Message);
Console.ReadLine();
}
Console.WriteLine(content);
Console.ReadLine();
}
}
}

出力:

C# メモリ リーク

C# メモリ リーク

C# で OutOfMemoryException を回避するには?

C# でのメモリ リークによる OutOfMemoryException を回避するために留意すべき点は次のとおりです。

  • イベントをサブスクライブしている場合は、イベントからイベント ハンドラーの登録を解除する必要があります。これは、IDisposable を実装することで実現できます。
  • 匿名メソッドでクラス変数の代わりにローカル変数をキャプチャすると、メモリ リークを回避できます。
  • アプリケーションで静的変数を過度に使用しないようにすると、特にこれらの変数が参照型である場合、メモリ リークの状況を回避できます。
  • アプリケーションにキャッシュ機能がある場合、特に長期間使用しない場合は、定期的にキャッシュをクリアする必要があります。キャッシュ サイズを制限したり、WeakReference を利用してキャッシュされたオブジェクトを保存したりすることもできます。
  • アプリケーション内のスレッドを適切に管理することで、メモリ リークを回避できます。

結論

アプリケーションが実行中に使用したメモリを解放しないと、このメモリはブロックされ、他のプロセスで使用できなくなり、メモリ リークが発生します。ガベージ コレクターは管理対象オブジェクトを自動的に破棄できますが、管理対象外のオブジェクトやリソースは破棄できません。

以上がC# メモリ リークの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。