StackOverflowException的常見幾種引起的方式
1.類的相互引用
2.方法的循環調用
3.屬性Set方法的死循環調用
class Program : IProgram { IPerson iPerson = new Person();//類的相互引用 static void Main(string[] args) { Person person = new Person(); person.InfiniteRecursion(1);//方法的循環調用 person.Name = "Ryzen"; person.Age = 23; person.Sex = "男";//屬性Set方法的死循環調用 Program program = new Program(); Console.WriteLine(program.iPerson.ReturnHello()); } public string RetrunWorld() { return "World"; }
}
public class Person : IPerson { IProgram iProgram = new Program(); public Person() { Console.WriteLine(iProgram.RetrunWorld()); } public int InfiniteRecursion(int a) { int b = a; return GetResult(b); } private int GetResult(int a) { int result = a + 1; return InfiniteRecursion(result); } public string ReturnHello() { return "Hello"; } #region 屬性 private string _name; public string Name { get { return _name; } set { _name = value; } } private int _age; public int Age { get { return _age; } set { _age= value; } } private string _sex; public string Sex { get { return _sex; } set { Sex= value; } } #endregion }
interface IProgram { string RetrunWorld(); } interface IPerson { string ReturnHello(); }
為什么會拋出該異常(棧溢出的異常)?
一.什么是棧?
首先我們知道在一個進程當中內存主要分為兩大區域:棧區和堆區,而每個進程當中又有一個或多個線程而棧區就是存在於每個一個線程當中,且每個線程存在初始化大小為1M,因此我們又把棧稱為線程堆棧,或者線程棧,而且線程棧是不受GC(垃圾回收機制)管理的,從溢出兩個字就可以說明棧其實是有一個空間大小的,當棧分配的空間不足以存放超過分配空間的大小的數據,就發生了棧溢出的情況下
在這里提一句解釋下堆區,堆區是一個進程在初始化的時候會在內存又划出一塊區域用來存儲某種類型的,而且受GC管理,因此又稱為托管堆而且托管堆區在32位系統在一個進程中能最多被分配1.5G的內存空間,在64位能分配8TB內存空間,因此我們很少會遇到堆的溢出,而且GC會在特定的時間釋放沒用到的堆空間,
首先我們知道棧是內存划分出來為一個區域專門為一個進程存放某種類型的數據,下面大概講解棧為存放那些類型的數據
1.參數:值參數,引用參數,輸出參數
2.局部變量
3.返回數據和返回地址
因此我們終於知道為什么方法的循環調用和屬性的Set方法的寫錯(屬性本質也是方法)以及類的循環調用會導致棧溢出異常的產生,因為方法的循環調用沒有返回,導致在一個進程當中的棧區域一直被填充,且線程棧其實在一個進程當中是有一定的空間的,直到填充超出了棧頂,因此溢出了
二.怎么快速確定什么原因排查到錯誤
這時候要請出我們宇宙第一IDE:Visual Studio,在調試的時候通過調用棧堆來觀看方法的調用,最頂層則是最新調用的一次方法從下圖在調用棧堆清晰可以看到是兩個類在初始化的時候互相調用了,調用棧堆和線程棧是一一對應的,當方法調用完后會釋放線程棧,則調用棧堆也會少一條信息
文章本着學習的目的,如果文章當中有不正確的地方或者有更好的解釋歡迎指點