很長時間沒有更新了,不是偷懶了,是偷偷學習了,我呢把我比較感興趣的部分,復述一遍,當然會有錯誤,并不是權威,希望大家指正,共同進步,
文章目錄
- 前言
- 一、物件在堆疊上分配
- 二、物件在EDEN分配
- 三、 minor GC 和 full GC
- 四、 物件進入老年代
- 3.1大物件直接進入老年代
- 3.2長期存活的物件將進入老年代
- 3.3物件動態年齡判斷
- 3.4老年代空間分配擔保機制
- 五、 物件頭
前言
其實整個JVM引數的調優,大體上就是圍繞著如何去減少垃圾回收的次數,盡可能地不要讓full GC發生,因為不管是哪一種垃圾收集器,都會有STW(Stop The Word)發生,就會影響用戶體驗,因此本次呢是先和大家一起學習下物件的分配規則,了解young GC 和 full GC分別是什么,有何種關系,以及物件進入老年代的一些機制等等,
一、物件在堆疊上分配
當創建出來的物件沒有被參考的時候就變成了垃圾,需要依靠GC進行回收,去釋放堆記憶體,如果物件數量較多的時候,會給GC帶來較大壓力,也間接影響了應用的性能,
為了減少臨時物件在堆內分配的數量,JVM通過逃逸分析確定該物件不會被外部訪問,如果不會逃逸可以將該物件在堆疊上分配記憶體,這樣該物件所占用的記憶體空間就可以隨堆疊幀出堆疊而銷毀,就減輕了垃圾回收的壓力,
物件逃逸分析: 就是分析物件動態作用域,當一個物件在方法中被定義后,它可能被外部方法所參考,則說明該物件會逃逸,不能讓它跟著堆疊幀一起銷毀,
成功逃逸:
public User getUser(){
User u = new User();
return u;
}
User物件通過return傳出這個方法外,顯然這個物件的作用域范圍不確定,就得在堆上創建了,
逃逸失敗:
public User getUser(){
User u = new User();
}
可以確定當方法結束這個User物件就是無效物件了,對于這樣的物件可以將其分配在堆疊記憶體里,讓其在方法結束時跟隨堆疊記憶體一起被回收掉,
當然,這個功能是可配置的,不喜歡你可以不要,恨了你可以拋棄,
JVM對于這種情況可以通過開啟逃逸分析引數
(-XX:+DoEscapeAnalysis)
來優化物件記憶體分配位置,使其通過標量替換優先分配在堆疊上(堆疊上分配),JDK7之后默認開啟逃逸分析,關閉使用引數
( -XX:-DoEscapeAnalysis)
標量替換: 通過逃逸分析確定該物件不會被外部訪問,并且物件可以被進一步分解時,JVM不會創建該物件,而是將該物件成員變數分解若干個被這個方法使用的成員變數所代替,這些代替的成員變數在堆疊幀或暫存器上分配空間,這樣就不會因為沒有一大塊連續空間導致物件記憶體不夠分配,
開啟標量替換引數(**-XX:+EliminateAllocations**),JDK7之后默認開啟,
標量與聚合量: 標量即不可被進一步分解的量,而JAVA的基本資料型別就是標量(如:int,long等基本資料型別以及reference型別等),標量的對立就是可以被進一步分解的量,而這種量稱之為聚合量,而在JAVA中物件就是可以被進一步分解的聚合量,
二、物件在EDEN分配
有的人一定和我一樣,看到EDEN這個名詞就很陌生,這什么鬼,這什么東西,其實就是堆中給分配的一塊區域,前面說了物件分配在堆疊上,如果不被分配到堆疊上那就只能分配在堆里了,那么EDEN又是堆中的…的…區域,

(媽的,…什么鬼?)
先請你看一下這張圖,這是堆中新生代的的區域,你也可以說是年輕代,對立面就是老年代了,簡單地理解一下,年輕代嘛,放年輕的物件(剛創建的物件),老年代就放創建比較久的物件,那么為什么要做這樣的區分? 這個后面3.2做出了解釋,下面會說到什么樣的算創建比較久的物件,或者說年齡比較大的物件,
那么,在新生代中,又分有EDEN區和兩個survivor區,Eden與Survivor區默認8:1:1,為什么是
因為新生代的物件幾乎都是朝生夕死的(創建完很快就沒用了),存活時間很短,所以JVM默認的8:1:1的比例是很合適的,讓eden區盡量的大,survivor區夠用即可,JVM默認有這個引數
-XX:+UseAdaptiveSizePolicy
(默認開啟),會導致這個8:1:1比例自動變化,如果不想這個比例有變化可以設定引數
-XX:-UseAdaptiveSizePolicy
三、 minor GC 和 full GC
minor GC: 當大量的物件被分配在eden區,eden區滿了年輕代就會觸發垃圾回收 - minor gc(,可能會有99%以上的物件成為垃圾被回收掉,剩余存活的物件會被挪到為空的那塊survivor區,下一次eden區滿了后又會觸發minor gc,把eden區和上一次用到的survivor區垃圾物件回收,把剩余存活的物件一次性挪動到另外一塊為空的survivor區,以此回圈,使得整個年輕代的空間可以重復使用,
full GC: 有沒有可能一個survivor區裝不下依然存活的物件,那么默認需要存活的物件超過survivor區的一半,就會將這些物件提前轉移到老年代,而老年代空間存滿之后發生的垃圾回收就叫做full GC
| 區域 | GC | 速度 |
|---|---|---|
| 年輕代 | minor GC | 快 |
| 老年代 | full GC | 慢 |
其實JVM調優部分引數也是圍繞著一個問題,如何盡量減少提前送養老的事情發生,因為 minor gc 是比較快的多得多的一種垃圾回收,一直送到老年代的話,老年代滿了是需要full GC的,這是比較慢的,會影響性能,
四、 物件進入老年代
3.1大物件直接進入老年代
大物件就是需要大量連續記憶體空間的物件(比如:字串、陣列),
JVM引數
-XX:PretenureSizeThreshold
可以設定大物件的大小,如果物件超過設定大小會直接進入老年代,不會進入年輕代,這個引數只在 Serial 和 ParNew兩個收集器下有效,
比如設定JVM引數:
-XX:PretenureSizeThreshold=1000000 (單位是位元組) -XX:+UseSerialGC
應該有人會問,為什么要直接進入老年代,剛才不還是說盡量減少物件提前送到老年代么?這怎么不等minor GC 就直接送進老年代了呢?
試想一下,如果好幾個大物件生成在年輕代,且在minor GC時,都還存在,大小一下子就超過了survivor區得一半,這樣就會帶著這幾個大物件以及其他存活得物件一起到老年代,顯然,如果提前把大塊頭送走,其他物件有可能不會超過一半就不用送到老年代了,
3.2長期存活的物件將進入老年代
虛擬機采用分代得思想分配記憶體,這種思想的目的是,有的物件存活比較久甚至永遠存在,這類物件每次參與GC的篩選等一系列操作,顯然也會占用一定的時間,所以這類物件放在老年代也省去了一直在復制到survivor區的動作可以提高性能,減少折騰,
那么記憶體回收時就必須能識別哪些物件應放在新生代,哪些物件應放在老年代中,為了做到這一點,虛擬機給每個物件一個物件年齡(Age)計數器,
如果物件在 Eden 出生并經過第一次 Minor GC 后仍然能夠存活,并且能被 Survivor 容納的話,將被移動到 Survivor空間中,并將物件年齡設為1,物件在 Survivor 中每熬過一次 MinorGC,年齡就增加1歲,當它的年齡增加到一定程度(默認為15歲,CMS收集器默認6歲,不同的垃圾收集器會略微有點不同),就會被晉升到老年代中(想想我要65歲才能退休,太慘了吧,我可以也15歲退休嗎?),
物件晉升到老年代的年齡閾值,可以通過引數 來設定,
-XX:MaxTenuringThreshold
3.3物件動態年齡判斷
Survivor區域里現在有一批物件,年齡1+年齡2+年齡n的多個年齡物件總和超過了Survivor區域的50%,
這個百分比有引數可以指定
-XX:TargetSurvivorRatio
此時就會把年齡n(含)以上的物件都放入老年代,
這個規則其實是希望那些可能是長期存活的物件,盡早進入老年代,這有什么好處呢,就不用一股腦,超過50%,就把年輕的老的全抓去養老院,這樣養老院也不會那么容易滿就不容易導致full GC的發生,
3.4老年代空間分配擔保機制
年輕代每次minor gc之前JVM都會計算下老年代剩余可用空間
如果這個可用空間小于年輕代里現有的所有物件大小之和(包括垃圾物件)
就會看老年代的可用記憶體大小,是否大于之前每一次minor gc后進入老年代的物件的平均大小,
如果上一步結果是小于或者之前說的引數沒有設定,那么就會觸發一次Full gc,對老年代和年輕代一起回收一次垃圾,

如果回收完還是沒有足夠空間存放新的物件就會發生"OOM"
當然,如果minor gc之后剩余存活的需要挪動到老年代的物件大小還是大于老年代可用空間,那么也會觸發full gc,fullgc完之后如果還是沒有空間放minor gc之后的存活物件,則也會發生“OOM”
老年代空間分配擔保機制可以通過引數配置是否生效
-XX:-HandlePromotionFailure
(jdk1.8默認就設定了)
五、 物件頭
這里想給大家看一下物件頭的一張表,暫時只先看下這張圖里的這個分代年齡,也就是說每個物件前面都跟著頭部,去記錄它的狀態,我們前面提到的物件年齡就是它每經歷一次minor GC 分代年齡就會+1.這個物件頭的內容,我想,慢慢的在每次用到的時候介紹一點,會更容易接受吧,因此這一次就介紹這么個分代年齡好了,

好了,我的筆記結束,下期再見!
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/289901.html
標籤:其他
上一篇:5分鐘通過水痘事件來認識系統架構
