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
usingchoIDisposable(FileStream, DbConnection, Bitmap...). - Unsubscribe event:
publisher.Event -= handler. - Tránh static collection giữ object lâu dài.
- Dùng
WeakReferencecho 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).