JVM調優總結(3):垃圾回收面臨的問題

如何區分垃圾

上面說到的「引用計數」法,經過統計控制生成對象和刪除對象時的引用數來判斷。垃圾回收程序收集計數爲0的對象便可。可是這種方法沒法解決循環引用。因此,後來實現的垃圾判斷算法中,都是從程序運行的根節點出發,遍歷整個對象引用,查找存活的對象。那麼在這種方式的實現中,垃圾回收從哪兒開始的呢?即,從哪兒開始查找哪些對象是正在被當前系統使用的。上面分析的堆和棧的區別,其中棧是真正進行程序執行地方,因此要獲取哪些對象正在被使用,則須要從Java棧開始。同時,一個棧是與一個線程對應的,所以,若是有多個線程的話,則必須對這些線程對應的全部的棧進行檢查。 java

同時,除了棧外,還有系統運行時的寄存器等,也是存儲程序運行數據的。這樣,以棧或寄存器中的引用爲起點,咱們能夠找到堆中的對象,又從這些對象找到對堆中其餘對象的引用,這種引用逐步擴展,最終以null引用或者基本類型結束,這樣就造成了一顆以Java棧中引用所對應的對象爲根節點的一顆對象樹,若是棧中有多個引用,則最終會造成多顆對象樹。在這些對象樹上的對象,都是當前系統運行所須要的對象,不能被垃圾回收。而其餘剩餘對象,則能夠視爲沒法被引用到的對象,能夠被當作垃圾進行回收。 算法

所以,垃圾回收的起點是一些根對象(java棧, 靜態變量, 寄存器…)。而最簡單的Java棧就是Java程序執行的main函數。這種回收方式,也是上面提到的「標記-清除」的回收方式 併發

如何處理碎片

因爲不一樣Java對象存活時間是不必定的,所以,在程序運行一段時間之後,若是不進行內存整理,就會出現零散的內存碎片。碎片最直接的問題就是會致使沒法分配大塊的內存空間,以及程序運行效率下降。因此,在上面提到的基本垃圾回收算法中,「複製」方式和「標記-整理」方式,均可以解決碎片的問題。 函數

如何解決同時存在的對象建立和對象回收問題

垃圾回收線程是回收內存的,而程序運行線程則是消耗(或分配)內存的,一個回收內存,一個分配內存,從這點看,二者是矛盾的。所以,在現有的垃圾回收方式中,要進行垃圾回收前,通常都須要暫停整個應用(即:暫停內存的分配),而後進行垃圾回收,回收完成後再繼續應用。這種實現方式是最直接,並且最有效的解決兩者矛盾的方式。 spa

可是這種方式有一個很明顯的弊端,就是當堆空間持續增大時,垃圾回收的時間也將會相應的持續增大,對應應用暫停的時間也會相應的增大。一些對相應時間要求很高的應用,好比最大暫停時間要求是幾百毫秒,那麼當堆空間大於幾個G時,就頗有可能超過這個限制,在這種狀況下,垃圾回收將會成爲系統運行的一個瓶頸。爲解決這種矛盾,有了併發垃圾回收算法,使用這種算法,垃圾回收線程與程序運行線程同時運行。在這種方式下,解決了暫停的問題,可是由於須要在新生成對象的同時又要回收對象,算法複雜性會大大增長,系統的處理能力也會相應下降,同時,「碎片」問題將會比較難解決。 線程

相關文章
相關標籤/搜索