1. 程式人生 > >引發型別為“System.OutOfMemoryException”的異常

引發型別為“System.OutOfMemoryException”的異常

在運維工作中,經常能接到客戶的反饋這個:引發型別為“System.OutOfMemoryException”的異常。客戶反饋實體記憶體都還有富餘,怎麼報記憶體不足的錯誤呢!

什麼時候會引發System.OutOfMemoryException:作業系統無法滿足GC對連續記憶體塊的請求,則會發生System.OutOfMemoryException

可能原因
1:記憶體真的不夠了,連虛擬記憶體都用完了。
2:記憶體還有,但碎片化嚴重,無法找到合適的連續記憶體塊。

一些常見的原因
1、系統裡快取了大量的資料,沒有及時釋放。應該控制快取的資料大小,快取失效的時間。
2、操作的大資料的檔案或者DataTable。應該分塊讀取。
3、本地資源洩漏。
解決方案:
3.1 應該及時釋放本地資源
3.2 使用IDisposable模式

4、大量的物件被固定,不能被壓縮移動,導致記憶體產生大量碎片。
解決方案:

4.1 如果固定物件大約在同一時間分配,則每兩個物件之間的碎片更小
4.2 優先初始化,因為較舊的物件位於堆的底部,但大多數可用空間都是在堆頂部生成的。
4.3 固定物件的時間越短,GC就越容易壓縮堆

測試環境:實體記憶體8G,64位作業系統
示例一、實體記憶體,虛擬記憶體都被消耗完,丟擲System.OutOfMemoryException的異常

using System;
using System.Collections.ObjectModel;

namespace OutOfMemoryExample
{
class Program { static List<byte[]> _root = new List<byte[]>(); static void Main(string[] args) { try { int i = 1; while (true) { var smallObject = new byte[64 * 1024];//小於85000byte的物件存在小物件堆(SOH – small object heap) Console.WriteLine(string.Format("{0}K", i * 64)); _root.Add(smallObject);
//用靜態List物件不斷新增小物件,由於靜態物件不會被回收,最終會發現實體記憶體和虛擬記憶體都耗盡,丟擲OutOfMemory異常 i++; } } catch (Exception ex) { Console.WriteLine(ex); } Console.Read(); } } } }

 

示例二、實體記憶體還有4G,虛擬記憶體都被消耗完(22G),丟擲System.OutOfMemoryException的異常。大物件為什麼都分配到虛擬記憶體上了,這一點我沒搞明白。

using System;
using System.Collections.ObjectModel;

namespace OutOfMemoryExample
{
class Program
{
static List<byte[]> _root = new List<byte[]>();
static void Main(string[] args)
{
try
{
for(int i=1;i<500000;i++)
{

var largeObject = new byte[100 * 1024];//大於85000byte的物件存在一個大物件堆(LOH –large object heap)
Console.WriteLine(string.Format("第{0}次:{1}K",i, i * 100));
_root.Add(largeObject);//用靜態List物件不斷新增物件,由於靜態物件不會被回收,最終會發現虛擬記憶體都耗盡,丟擲OutOfMemory異常!但實體記憶體還有4G
i++;
}
}
catch (Exception ex)
{
Console.WriteLine(ex);
}

Console.Read();
}

}
}