垃圾回收--代
垃圾回收--代
代是CLR垃圾回收器采用的一種機制,他唯一的目的就是提升應用程序的性能,采用代的垃圾回收器做到了一下幾點:
1:對象越新,生存周期越短,跟棧的原理很像,先進后出,先定義的局部變量,在棧中停留的時間相對長一點。
2:對象越老,生存周期越長,后面解釋。
3:回收堆的一部分,速度快于回收整個堆,那是肯定的,就是為了實現只回收一部分內存中的數據,才產生了代的概念,大多數時間只回收第0代。
第0代:托管堆在初始化的時候不包含任何對象,新分配在堆上的對象被稱為第0代,垃圾回收器從沒有檢查過他,CLR在初始化的
時候,會為第0代預算了一個容量,假設為256KB,容量一般為128KB的整數倍,這跟CPU的L2緩存容量有關,CPU的L2緩存容量經
歷了128KB,256KB,512KB,1M......,就是為了讓第0代中的數據能全部裝入CPU的L2緩存中,這樣處理數據會更快。
第1代:如果在分配一個新對象時,使第0代中的數據超過其預算容量,就會發生垃圾回收,不能到達的數據就會被回收,不能到
達就是沒有被任何對象引用,有被引用當然就不會被回收,沒有被回收的數據,被稱為第1代,第一代的容量比第0代的大,假設
為2M,經過一次垃圾回收后第0代不包含任何數據。只要第1代沒有就不會回收。
新產生的對象永遠被分配在第0代中,第0代中的數據滿了,就發生垃圾回收,將沒有被回收的對象壓縮至第1代,數據壓縮相當耗
性能,就是把數據從內存在的A出復制到內存的B處,只要第1代中的數據沒有滿,垃圾回收器就只會回收第0代中的數據,這就是
部分回收,當第1代中的數據滿了,垃圾回收器就會同時回收第0代和第1代,第0代沒有被回收的數據就會被壓縮到第1代中,直至
第1代也滿。
第2代:當第1代中的數據滿了,就會回收第1代,沒有被回收的數據就被稱為第2代,第2代的容量大于第1代,托管堆只支持3代
,第0代,第1代,第2代。
CLR假設新生成的對象生存周期較短,所以每次回收第0代都能回收大量內存,所以CLR總是針對第0代瘋狂的回收,這樣效率高嗎
?哈哈哈!這樣可能導致第0代被回收了很多次,第1代一次也沒有被回收,當然第1代中大垃圾也就沒有被回收,CLR假設活得比
較久的對象能繼續活下去,這就是對象越老,生存周期越長。
托管堆只實現部分回收,即回收第0代,由于第0代的容量較小,所以每次垃圾回收的速度較快,當然也會因為第0代容量較小,發
生垃圾回收的頻率會高一些,為了得到更好的垃圾回收性能,所以第0代的容量是動態的,如果每次執行垃圾回收,所有的垃圾都
被回收了,那么托管預算第0代的容量就會減少,這樣可以加快垃圾回收的速度,如果每次執行垃圾回收,都有大量的垃圾沒有被
回收,從第0代變成第1代,托管堆就會將第0代的預算容量變大,這樣可以減少數據的轉移。數據的轉移就相當于整理內存碎片,
對程序的性能,影響還是蠻大的。
只回收第0代的還有一個好處就是,如果第0代中的數據引用了第1代中的數據,第1代中的數據不用被檢查,第1代中被引用的對象
內部結構,垃圾回收器也不會管,回收更快啊,當然第1代中的數據也可能引用第0代中的數據,若第1代中的對象引用了第0代中
的對象,第1代中的對象就會被標記,只有重上一次垃圾回收到下一次垃圾回收被標記的對象才會被檢查,當然要檢查第1代中的
數據啊,你不檢查第1代中的數據,你怎么知道第0代中的數據不可到達,沒有被引用呢,第1代中,只有被標記的對象才會被檢查
,這樣同樣能提高垃圾回收的性能。總之,微軟設計的這個垃圾回收器處處在提高你的程序性能,他是這么說的,你感覺到了嗎?
如果回收3代還是沒有內存可分配,就拋出一個OutOfMemoryException異常,告訴你沒有內存可分配了,以前在開發一個項目中
就偶爾拋出這個異常,當時我們都不知道怎么回事,原因就是我們構造一個大的Json對象,用的是string+string,導致內存被
吃光了,要是當時知道用StringBuilder,性能將會大大的提高,也不至于OutOfMemoryException異常啊,哈哈哈。
作者:陳太漢
浙公網安備 33010602011771號