背景
與C++對比,C++的內(nèi)存回收是有C++的代碼控制的嫁蛇,而JAVA的內(nèi)存回收是由JVM的垃圾回收器控制的齿坷,看起來JAVA的垃圾回收更“自動化”,但是當需要排查內(nèi)存溢出和內(nèi)存泄漏問題時狰闪,垃圾回收器成為系統(tǒng)的瓶頸疯搅,此時就需要對這些“自動化”的技術實施監(jiān)控和調節(jié)濒生。
- 內(nèi)存溢出:程序報警分配的內(nèi)存空間不夠用
- 內(nèi)存泄漏:是指程序在申請內(nèi)存后,無法釋放已申請的內(nèi)存空間幔欧,一次內(nèi)存泄露危害可以忽略罪治,但內(nèi)存泄露堆積后果很嚴重,無論多少內(nèi)存,遲早會被占光礁蔗。
- 內(nèi)存泄漏會導致內(nèi)存溢出
GC的區(qū)域
jvm的運行時數(shù)據(jù)區(qū)主要分為方法區(qū)觉义、堆、虛擬機棧浴井、本地方法棧晒骇、程序計數(shù)器。
其中磺浙,虛擬機棧洪囤、本地方法棧、程序計數(shù)器是線程私有的撕氧,一旦線程執(zhí)行完成瘤缩,內(nèi)存就會自然回收。
方法區(qū)伦泥、堆是線程共用的剥啤,不會隨著線程結束而回收锦溪,所以GC主要是針對方法區(qū)和堆。
GC的的目標對象
決定對象的內(nèi)存空間是否需要被回收府怯,主要由兩種方式引用計數(shù)和可達性分析
引用計數(shù)
引用計數(shù)的方式可以簡單高效的實現(xiàn)刻诊,但是因為存在缺陷(一旦出現(xiàn)循環(huán)引用則永遠不能被回收),所以沒有的jvm的GC中是用富腊,
可達性分析
可達性分析是指從GC ROOTS出發(fā)坏逢,根據(jù)依賴關系是否可以達到指定的對象,如果可達赘被,則對象不能被回收是整,如果不可能,則對象可以被回收民假。
另外浮入,除了強引用外,還有軟引用羊异、弱引用事秀、虛引用等,主要一次隨著應用強度而減弱野舶,而在空間回收時易迹,按照相反次序進行內(nèi)存回收。
GC roots的對象主要擴一下四種:
- 虛擬機棧引用的對象
- 本地方法棧應用的對象
- 方法區(qū)引用的對象
- 常量池引用的對象
GC的算法
垃圾回收的算法主要包括四種:
- 標記-清除
- 標記-復制
- 標記-整理
- 分帶收集算法
標記-清除
一次標記平道,一次請求睹欲,缺點是回收效率低,并且造成大量的內(nèi)存碎片一屋,雖然有諸多缺點但是卻是其他后續(xù)的算法的基礎
標記-復制
將空間分成相等的兩部分窘疮,每次只使用一塊,雖然效率提高冀墨,但是也造成了大量的空間浪費
標記-整理
在“標記-清除”的基礎上闸衫,對剩余的空間進行碎片整理,這樣提高了空間的使用率诽嘉,降低了下次分配內(nèi)存空間因為連續(xù)空間不足而導致需要再次GC的問題
分帶收集算法
根據(jù)對象的生命周期特性蔚出,90%以上新生對象是很快就要被回收的,所以整體上將內(nèi)存空間分為新生代和老年代虫腋,并且將新生代分為Eden和兩個相等的Survivor區(qū)骄酗。新生對象分配的空間在Eden和一個survivor中,每次minor GC后岔乔,將存貨的對象負責到另一個survivor上酥筝。
默認參數(shù)-XX:SurvivorRatio=8
Eden:s0:s1=8:1:1
GC的類型
- serial
- ParNew
- CMS
- Parallel
- parallel Old
- serial old
- G1
GC的日志
- 進程實例運行時間
- GC類型
- GC區(qū)域
- 區(qū)域的內(nèi)存空間變化
- 實例的內(nèi)存空間變化