當須要排查各類內存溢出,內存泄漏問題時,當垃圾收集成爲系統達到更高併發量的瓶頸時,咱們就須要對這些自動化的技術實施必要的監控和調節。java
在前面一章瞭解到java內存的運行時區域,對於程序計數器,虛擬機棧,本地方法棧三個區域隨線程而生,隨線程而滅,且棧中的每個棧幀分配多少內存基本上是在類結構肯定下來時就已知的,所以,這幾個區域的內存分配和回收都具有肯定性,所以不須要加多考慮。算法
而java堆和方法區不同,一個接口中的多個實現類須要的內存可能不同,一個方法中的多個分支須要的內存也不同,咱們只有在程序處於運行期間時才能知道會建立哪些對象,這部分的內存分配和回收都是動態的,所以,垃圾收集器所關注的就是這部分的內存多線程
垃圾收集也叫GC,GC須要作如下三件事情:併發
1)如何斷定對象爲垃圾對象?高併發
答:策略有引用計數法和可達性分析法spa
2)如何進行垃圾回收?線程
答:策略有:標記-清除算法,複製算法,標記-整理算法,分代收集算法3d
垃圾收集器有:Serial ,parnew,CMS,G1對象
3)什麼時候進行垃圾回收?blog
如何斷定對象爲垃圾對象?
1,引用計數法: 在對象中添加一個引用計數器,當有地方引用這個對象的時候,引用計數器的值+1,當引用失效的時候,計數器的值-1。
當值被判爲0的時候就進行回收
存在問題:當對象進行循環引用時,致使他們的引用計數都不爲0,就不能分析對象爲垃圾對象
優勢是比較靈活
2,可達性分析法:經過一系列的名爲「GC Roots」 的對象做爲起點,從這些節點開始往下搜索,搜索所走過的路徑成爲引用鏈。當一個GC Roots到這個對象不可達時,則證實此對象是不可用的,此時會將該對象斷定爲垃圾對象。
在java語言中,可做爲GC Roots的對象包括下面幾種:
1)虛擬機棧(棧幀中的局部變量表)
2)方法區的類屬性所引用的對象
3)方法區中的常量所引用的對象
4)本地方法棧中的引用的對象
目前斷定是否爲垃圾的算法均是可達性分析算法
如何進行垃圾回收?
1,標記-清除算法:算法分爲「標記」和「清除」兩個階段,首先標記出全部須要回收的對象,在標記完成後統一回收掉全部被標記的對象
它的缺點:一個是效率問題,標記和清除的過程都不高,另外一個是空間問題,標記清除以後會產生大量不連續的內存碎片,空間碎片太多會致使,當程序在之後的運行過程當中須要分配較大對象時沒法找到足夠的連續內存而不得不觸發另外一次垃圾收集的動做。
2,複製算法:針對新生代內存進行回收
解決標記-清除算法的效率問題,它將可用內存按容量劃分爲大小相等的兩塊,每次只使用其中一塊,當這一塊的內存用完了,就將還存活的的對象複製到另一塊上面,而後再把已使用的內存空間一次清理掉
上述算法會引來一個新的問題:形成內存資源極大的浪費,咱們來按如下方法分配內存空間:
將內存分爲一塊較大的Eden空間和兩塊較小的Servivor空間,每次使用Eden和其中的一塊Servivor。當回收時,將Eden和Servivor中還存活着的對象一次性的拷貝到另一塊Servivor空間上,最後清理掉Eden和剛纔使用過的Servivor的空間
3,標記整理算法:針對老年代內存進行回收,也叫標記,整理,清除,整理階段須要將存活對象排序整理好
4,分代收集算法:
對於新生代選擇複製算法,對於老年代,選擇標記整理算法
垃圾回收器:垃圾回收器就是垃圾回收的具體體現
介紹HotSpot JVM 1.6的垃圾收集器:兩個收集器之間存在連線,就說明它們能夠搭配使用
Serial收集器:它是一個單線程的收集器,在它進行垃圾收集時,必須暫停其餘全部的工做線程,直到它收集結束
它是虛擬機運行在client模式下的默認新生代收集器,有着優於其餘收集器的地方:簡單而高效,對於限定單個CPU的環境來講,Serial收集器優 於沒有線程交互的開銷,專心作垃圾收集天然能夠得到最高的單線程收集效率。
ParNew收集器:是Serial收集器的多線程版本,除了使用多線程進行垃圾收集以外,其他行爲包括Serial收集器可用的全部控制參數,收集算法,對象分配規 則,回收策略等都與Serial收集器徹底同樣。