首頁  >  文章  >  後端開發  >  C# 記憶體洩漏

C# 記憶體洩漏

王林
王林原創
2024-09-03 15:21:56397瀏覽

記憶體洩漏是指程式或應用程式長時間使用系統主記憶體時發生的情況。當程式在執行過程中不釋放其佔用的記憶體時,即使在完成執行過程後,分配的記憶體空間也會降低系統的效能並導致系統無回應。在本主題中,我們將學習 C# 記憶體洩漏。

釋放未使用的已分配記憶體是垃圾收集器的責任,但我們仍然會遇到記憶體洩漏的問題,因為我們有時會從在整個應用程式的生命週期中從未超出範圍的變數引用未使用的對象。

文法

C#中有很多方法可以避免記憶體洩漏;在使用非託管資源時,我們可以藉助「using」語句來避免記憶體洩漏,該語句內部呼叫 Dispose() 方法。 ‘using’語句的語法如下:

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

上面的語句中,‘var’是關鍵字,用於儲存任意類型的數據,編譯器可以在編譯時判斷出該數據類型。 “objectName”是任何使用者定義的物件名稱。 ‘new’是用來初始化物件的關鍵字,‘AnyDisposableType’可以是任何類,如 StreamReader、BinaryReader、SqlConnection 等,其物件可以透過 ‘using’ 語句來處理。

C# 中的記憶體洩漏是如何發生的?

對於.NET應用程序,我們有一個垃圾收集器來處理未使用的內存,但我們仍然遇到內存洩漏的問題。這並不意味著垃圾收集器無法正常工作,而是由於程式設計師的一些無知而發生這種情況。

假設我們在很長一段時間內忽略應用程式中的記憶體洩漏。在這種情況下,我們會增加應用程式的記憶體消耗,這會降低應用程式的效能並逐漸破壞它,從而引發 OutOfMemoryException。

C# 中記憶體洩漏的主要原因有兩個:

  • 第一個原因是有一個不再需要的未使用對象,但仍被變數引用,該變數在整個應用程式的生命週期中都有其作用域。由於該物件具有引用,因此它不會被垃圾收集器銷毀,並且將永遠保留在記憶體中,並且可能成為記憶體洩漏的原因。這種情況的一個例子是我們已經註冊但從未取消註冊的事件。
  • 第二個原因是為非託管資源分配了內存,然後在使用後沒有釋放它。與託管資源一樣,非託管資源無法自動進行垃圾收集。因此,程式設計師有責任在使用後釋放該記憶體。

導致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 來做到這一點。
  • 在匿名方法中捕獲局部變數而不是類別變數可以避免記憶體洩漏。
  • 避免在我們的應用程式中過度使用靜態變量,特別是當這些變數是引用類型時,我們可以避免記憶體洩漏的情況。
  • 如果我們的應用程式有快取功能,那麼我們需要定期清除緩存,特別是當它長時間不用時。我們還可以限制快取大小,並可以利用 Wea​​lReference 來儲存快取物件。
  • 正確管理應用程式中的執行緒可以避免記憶體洩漏。

結論

當應用程式沒有釋放其執行過程中使用的記憶體時,該記憶體將被阻塞,無法被任何其他進程使用,從而導致記憶體洩漏。垃圾收集器可以自動處置託管對象,但無法處置非託管對像或資源。

以上是C# 記憶體洩漏的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn