StackOverflowException
當執行緒啟動執行的時候,預設會保留 1MB 的記憶體,這個記憶體就是所謂的堆疊 (Stack);而我們使用的資料型別若為實值型別
(Value Type
),這個時候,這些物件將會儲存在堆疊內;另外,當我們進行函式呼叫的時候,也會用到這個堆疊記憶體,只要結束函數執行,相關的記憶體會就自動歸還給堆疊,下次有其它函式要進行呼叫的時候,就可以重複繼續使用些堆疊記憶體。最後,.NET 記憶體回收機制,是不會來處理堆疊內的無參考記憶體的回收工作的。OutOfMemoryException
關於參考型別所實例化出來的執行個體(物件),當時的物件變數,實際上儲存的是堆積 (Heap) 上的某塊記憶體空間,也就是說,這個物件變數,儲存著一個參考
,這個參考
會指向堆積上的某個記憶體位置。當我們對於堆積上的物件不再使用的時候,也就是說,該物件沒有任何參考指向它,此時,.NET系統的 Garbage Collection 記憶體回收機制,會將這些沒有人參考的 Managed 記憶體進行回收,程式開發者不需要去處理這些記憶體回收的工作。因此,當堆積 Heap 的記憶體不夠用的時候,就會出現這個錯誤例外異常。
底下是我們要測式的兩種型別
MyStruct
其型別為結構,屬於實值型別,也就是會使用堆疊記憶體。MyLargeClass
與MySmallClass
其型別為類別,屬於參考型別,所產生的執行個體,將會儲存在堆積內。前者將會產生出大於 85000 bytes 的堆積空間的執行個體,而後者將會產生出小於 85000 bytes 的堆積空間的執行個體;我們將會使用這兩個類別所產生的執行個體,分別檢測 .NET 記憶體回收機制中,對於大型物件與小型物件的記憶體使用不足情況之測試。
public struct MyStruct
{
public double X;
public double Y;
}
public class MyLargeClass
{
// 這將會讓產生的執行個體會占用 > 85000 bytes 的記憶體大小
public byte[] bytes = new byte[1024 * 86];
}
public class MySmallClass
{
// 這將會讓產生的執行個體會占用 < 85000 bytes 的記憶體大小
public byte[] bytes = new byte[1024 * 20];
}
進行測試
首先,我們來進行造成
StackOverflowException
例外異常的模擬測試,在這裡,我們設計一個遞迴呼叫函式,在這個函式裡面,會使用到一個結構物件,該結構物件將會耗用堆疊記憶體,由於該函式會無窮盡的呼叫自己,最終將會造成堆疊記憶體不足的情況發生。 static void Main(string[] args)
{
long level = 0;
Recursive(level);
}
private static void Recursive(long level)
{
MyStruct structObject;
structObject.X = level;
level++;
Recursive(level);
}
接著,我們來模擬堆積的記憶體耗盡的情境,由於 .NET 記憶體回收機制對於大型物件(大於 85000 Bytes)與小型物件的處理方式不同,所以,底下程式碼將會是進行大型物件的大量物件產生模擬;由於這些大物件產生之後,都會持續有參考到該物件,因此,GC是不會針對這些物件進行記憶體回收,最終會造成堆積記憶體耗盡,系統就會顯示
OutOfMemoryException
例外異常錯誤訊息。 List<MyLargeClass> listObject = new List<MyLargeClass>();
for (int i = 0; i < 1000 * 1000; i++)
{
listObject.Add(new MyLargeClass());
}
}
我們使用同樣的手法,只不過這次進行產生大量的小物件,並且這些小物件持續有參考指向該小物件,當然,最終還是會造成堆積記憶體耗盡,系統就會顯示
OutOfMemoryException
例外異常錯誤訊息。 List<MySmallClass> listObject = new List<MySmallClass>();
for (int i = 0; i < 1000 * 1000; i++)
{
listObject.Add(new MySmallClass());
}
}
了解更多關於 [C# 程式設計手冊]
StackOverflowException
與OutOfMemoryException
,他們分別表示了這個應用程式已經沒有足夠可用的記憶體,在這份練習中,將會展示出,造成這兩個例外異常的現象。