Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> C#

Xử lý ngoại lệ OutOfMemoryException trong C#

OutOfMemoryException ném ra khi Common Language Runtime (CLR) không thể cấp phát đủ bộ nhớ cho yêu cầu. Thường xảy ra khi:

  • Tạo đối tượng quá lớn (> 2GB trên 32-bit, > GC heap limit).
  • Rò rỉ bộ nhớ (memory leak) do giữ reference không cần thiết.
  • Xử lý dữ liệu lớn không dùng streaming (load toàn bộ file 10GB vào RAM).
  • StringBuilder với capacity quá nhỏ rồi thêm dữ liệu lớn.

Ví dụ gây lỗi (StringBuilder capacity cố định)

using System;
using System.Text;

class Program
{
    static void Main()
    {
        try
        {
            string name = "Tom";
            string subject = "Mathematics";
            
            // Capacity = Length ban đầu (3), MaxCapacity = Length (3) -> KHÔNG MỞ RỘNG
            StringBuilder sb = new StringBuilder(name.Length, name.Length);
            sb.Append(name); // "Tom" - OK
            
            // Thử chèn thêm -> Vượt MaxCapacity -> OutOfMemoryException
            sb.Insert(name.Length - 1, subject, 1); 
        }
        catch (OutOfMemoryException ex)
        {
            Console.WriteLine("Lỗi: " + ex.Message);
        }
    }
}

Kết quả

Lỗi: Out of memory

Cách xử lý đúng

1. Không giới hạn MaxCapacity (mặc định)

// Chỉ set capacity ban đầu, để tự mở rộng
var sb = new StringBuilder(100); // Capacity 100, MaxCapacity int.MaxValue
sb.Append("Tom");
sb.Insert(2, "Mathematics"); // OK, tự mở rộng

2. Xử lý dữ liệu lớn: Streaming, không load all

// SAI: Load file 10GB vào string/byte[]
string content = File.ReadAllText("huge.log"); // OutOfMemory!

// ĐÚNG: Stream line by line
using (var reader = new StreamReader("huge.log"))
{
    string line;
    while ((line = reader.ReadLine()) != null)
    {
        ProcessLine(line); // Xử lý từng dòng
    }
}

3. Dispose đúng, tránh memory leak

  • Dùng using cho IDisposable (FileStream, DbConnection, Bitmap...).
  • Unsubscribe event: publisher.Event -= handler.
  • Tránh static collection giữ object lâu dài.
  • Dùng WeakReference cho cache.

4. Cấu hình GC cho ứng dụng lớn

// App.config / runtimeconfig.json
<configuration>
  <runtime>
    <gcAllowVeryLargeObjects enabled="true" /> <!-- Cho mảng > 2GB trên 64-bit -->
    <gcServer enabled="true" /> <!-- Server GC cho throughput cao -->
  </runtime>
</configuration>

Lưu ý quan trọng

  • Không nên catch OutOfMemoryException để tiếp tục chạy. Trạng thái tiến trình không xác định, có thể corrupt data.
  • Thay vào đó: Phòng tránh (streaming, pooling, sizing), Giám sát (dotnet-counters, PerfView, GC logs).
  • Trên 32-bit process: giới hạn ~2GB virtual address space. Luôn compile/run 64-bit (Prefer 32-bit = false).