深入研究java gc
深入研究java gc
題外話:什麽是java程序的執行流程;java運行時數據區;java的內存管理 見如下圖:
java程序執行流程:
java運行時數據區:
java的內存管理:
在我們(運行時數據區)之中,內存的分配一共有五塊:
1、堆內存(Heap):保存真正的程序的數據的部分;
2、&&&棧內存(Stack):保存堆內存地址、還保存基本數據、方法的執行;(所有的數據都在棧內存之中)
3、方法區:保存所有方法的具體的操作,該區域屬於共享;
4、程序計數器:這是一塊很小的內存,小到幾乎可以忽略的地步,只是做一個程序執行順序的記錄,只是為了標記我們下一步要執行的代碼的順序號;
我們關心的主要是堆內存、棧內存、方法區
在整個的JVM內存組成過程之中,(棧內存)是一個非常重要的概念,因為在該內存之中,他需要保存的數據是一組內容,
因為所有的方法在進行遞歸調用的時候都會采用棧的模式。觀察遞歸問題中滿棧的原因取決於服務器內存的大小。
內存操作有關的兩類異常
stackOverFlowError(棧溢出):如果請求的棧的深度過大,虛擬機可能會拋處。
OutOfMemoryError(內存溢出):如果虛擬機的實現中允許、虛擬機棧動態擴展,當內存不足以擴展棧的時候,會拋出。【內存被沾滿,更多情況下表示堆也分配不了了】
實際上上面只是觀察到了兩類可能出現錯誤的代碼,但是並不是意味著棧中只能夠保存一下基本的信息,實際上棧裏面保存同樣是一組的數據。
總結:
1、造成stackOverFlowError(棧溢出)OutOfMemoryError(內存溢出)的原因是;
2、在JVM棧內存中保存有棧幁的概念,所有的棧內存采用先進後出的數據結構來進行我們的存儲。
首先需要了解一下什麽是java的堆內內存劃分
在實際情況下:java 堆內存劃分分為了(jdk1.8以前和jdk1.8之後)【對於這2者的區別,我們後面介紹】
jvm堆內存劃分(jdk1.8以前):
jvm堆內存劃分(jdk1.8之後):
java堆內存模型
java的垃圾收集主要指的是java堆內存空間,那麽在每一次執行GC的時候需要區分出那些堆內存空間需要被回收,那些不應該被回收。 所以為了整個的回收處理方便,JVM將堆內存分為如下的幾個組成部分。而這幾個組成部分你還需要去考慮JDK的版本,現在的JVM內存劃分就必須考慮JDK1.8以前和JDK1.8之後的問題了。
1、新生代:那些剛剛創建的對象,剛剛創建的對象有可能會存在有許多垃圾對象,那麽這些對象應該是被優先回收的;
2、老年代:老不死的那類對象,經過了很多次的清理之後你發現該對象依然有用,
3、永久代:intern()方法進行入池的對象實際上就在永久代中,永久代不會被回收。因為其本身屬於一個bug性的存在(也就是jdk崩潰了,死了永久代CIA能消失),所以在jdk1.8之後,將其更換為元空間(就是電腦的直接內存)。
舉個例子:我電腦有100G內存,80G給了堆內存,那剩下的20G就可以給元空間。
在整個內存的組成過程之中,每一代的內存空間都會有一個伸縮區,那麽該區域就可以由JVM根據空間的使用情況,動態擴充。
當我們適當合理的設置了伸縮區的內存大小之後,那麽就可以得到良好的性能提升。也就是說最容易的性能提升就是改變伸縮區的內存大小。
首先什麽是java gc 、java對象創建流程
java對象創建流程如圖:
1、大多數內存對象要麽生存周期比較短,很快就會沒人引用,比如處理RPC請求的buffer可能只會生存幾微秒;
2、要麽生存周期比較長,比如Block Cache中的熱點Block,可能就會生存幾分鐘,甚至更長時間。
3、基於這樣的事實,JVM將整個堆內存分為兩個部分:新生代(young generation)和老生代(tenured generation),除此之外,JVM還有一個非堆內存區-Perm區,主要存放class信息以及其他meta元信息,
4、其中Young區又分為Eden區和兩個Survivor 區:S0和S1。
5、一個內存對象在創建之後,首先會為其在新生代申請一塊內存空間,如果這個對象在新生代存活了很長時間,會將其遷移到老生代。
6、在大多數對延遲敏感的業務場景下(比如HBase),建議使用如下JVM參數,-XX:+UseParNewGC和XX:+UseConcMarkSweepGC,其中前者表示對新生代執行並行的垃圾回收機制,而後者表示對老生代執行並行標記-清除垃圾回收機制。
7、可見,JVM允許針對不同內存區執行不同的GC策略。
接下來重點先討論一下年輕代
年輕代GC實現算法:
深入研究java gc