遞歸在多層次遍歷時尤其重要,這裏咱們不講遞歸的實現,來談談遞歸的內存佔用狀況。多線程
以下代碼,當咱們運行時很簡單,StackOverflowException瞬間拋出;這裏確實是「瞬間」出錯了,線程堆棧溢出;spa
首先咱們要理解,一個程序是在一個進程下運行的,進程下能夠有不少線程執行,可是每個線程能佔用的內存控件是有限的,大約1M,當一個線程佔用超過1M時,就會StackOverflow了;存放在線程堆棧上的有方法中的值類型變量,和引用變量的指針地址。理解這些能幫咱們分下,遞歸爲何致使StackOverflow了。線程
static void Main(string[] args) { Main(args); }
這裏咱們作一個簡單的分析,不考慮不重要的因素:指針
首先,線程執行Main方法,首先方法總沒有值類型變量,只有數據args,全部只有args的指針地址存放在線程堆棧上,佔4byte,Main中有調用Main方法,如此遞歸調用,就至關於(4+4+4……+4)bytes,最終達到1M,致使StackOverflow異常。有CLR拋出異常。code
固然這裏線程執行方法只是一個簡單的分析,實際狀況很複雜,好比,進入方法,會有一個專門的表維護方法信息,方法的返回地址,參數,局部變量,這些都佔用線程堆棧空間,方法返回時,全部方法佔用的內存被釋放。而上述遞歸,永遠不存在方法返回,因此資源不會被釋放,最終拋出異常。blog
若是說上述很簡單理解,那咱們加倆行代碼:遞歸
static void Main(string[] args) { GC.Collect(); GC.WaitForFullGCComplete(); Main(args); }
這樣執行方法,這個代碼是我從某論壇的一個版主那裏看來的,他說這樣就不會致使StackOverflow了,結果下面的一羣人深信不宜,我感受遞歸確定資源耗盡,只是GC不能回收線程堆棧內存,可是當我在代碼上運行時,上述代碼確實不報錯,一直運行着,當時納悶難道我理解錯誤,這不科學!我一直等着,果真過了1分鐘多,我期待的StackOverflow出現了,內心竊喜。進程
可是我自己也不是很理解,爲何加了上面的兩句話致使,要等那麼久才移除,很奇怪。我問了問別人,結果實驗了一下,將GC代碼去掉,僅僅加一個Thread.Sleep(5),也會致使很長時間才拋出異常,費解中,最後我寫了以下代碼:內存
static int a = 0; static void Main(string[] args) { a++; Console.WriteLine(++a); Main(args); }
我看下方法遞歸多少次,我電腦上是a=12萬多,也就是最終方法遞歸了12萬屢次拋出了StackOverflow,全部上面的Thread.Sleep(5)執行長時間才報錯也能夠的出結論了,每一遞歸一次方法聽5毫秒,遞歸1萬次就是50秒,因此,結論不是GC回收影響遞歸長時間不報錯,而是,每次執行GC,線程Sleep的時間,讓我感受長時間不報錯。資源
上面問題自己沒有多大意義,僅僅做爲筆記記錄一下,一樣本身也更深刻理解了內存佔用。