JVM性能調優 第七章 內存分配策略
理解了jvm內存分配策略不僅是程序性能調優的重要知識,還能夠給養成自己一種良好的代碼思路,一個程序的代碼差異往往都是在這裏體現出來的。
一、對象優先分配到Eden區域
一般來說,新創建的對象都會直接分配到Eden區域,如果Eden區域內存不夠,JVM就會觸發GC(垃圾回收),一般來說在JVM中有3種GC:
Minor GC:指發生在新生代的垃圾收集動作,非常頻繁,速度較快。
Major GC:指發生在老年代的GC,出現Major GC,經常會伴隨一次Minor GC,同時Minor GC也會引起Major GC,一般在GC日誌中統稱為GC,不頻繁。
Full GC:指發生在老年代和新生代的GC,速度很慢,需要Stop The World。
所以在Eden區域中發生的GC就是Minor GC,在虛擬機中,可以設置Eden區域的大小從而調節Minor GC的頻率,參數為:
-Xmx10240m -Xms10240m -Xmn5120m -XXSurvivorRatio=3
其中:
-Xmx:最大堆大小
-Xms:初始堆大小
-Xmn:年輕代大小
-XXSurvivorRatio:年輕代中Eden區與Survivor區的大小比值,即Eden區域內存/Survivor區域內存的值
二、大對象直接分配到老年代
那麽多大的對象算是大對象呢?一般來說,這個定義大對象的值可以通過虛擬機的參數來設置:
-XX:PretenureSizeThreshold=XX
如果大於XX的對象就會直接分配到老年代, 為什麽大對象要直接分配到老年代?
一般認為大對象為長字符串,存活較久,如果進入新生代,因為eden中的GC回收頻率較高,大對象在進行對象標記算法時會影響到JVM的性能。
三、長期存活的對象進入老年代
這個應該很好理解,長期存活的對象證明該對象的引用頻率較高,所以放入老年代中可以更好的提高eden中內存的大小。存活多久才算長期存活?
在JVM觸發GC回收Eden區域後,還存活的對象就會復雜到Survivor區域整,該區域中有年齡存活計數器,設置年齡為1,對象在Survivor區每次經過一次Minor GC,年齡就加1,當年齡達到一定程度(默認15),就進入到老年代,
年齡可以通過虛擬機的參數來設置:
-XX:MaxTenuringThreshold
四、空間分配擔保
所謂的空間分配擔保是指:在新生代內存不夠時即發生了Minor GC,向老年代借內存的情況就是空間分配擔保。要驗證如果老年代的連續空間大於新生代對象總大小或者歷次晉升的平均大小就會進行Minor GC,否則將進行Full GC,如果發生了Full GC將會大大降低程序性能,最簡單的情況就是程序會出現非網絡原因的卡頓。
五、動態對象年齡判斷
對象的年齡到達了MaxTenuringThreshold可以進入老年代,同時,如果在survivor區中相同年齡所有對象大小的總和大於survivor區的一半,年齡大於等於該年齡的對象就可以直接進入老年代。無需等到MaxTenuringThreshold中要求的年齡。
六、逃逸分析與棧上分配
這個策略是在JVM棧中進行的。由於jvm棧內存是在方法獨占區中,每一次程序運行完畢後,棧上的內存隨著方法的執行來分配空間,且棧幀出棧時會消滅空間,因此不會進行GC回收。棧上分配後,JVM的性能會很快,所以在編寫代碼過程中,優先考慮棧上分配來寫代碼是個很好的代碼習慣。
那麽什麽情況下,可以使用棧上分配,這就需要在對代碼進行逃逸分析:我們要分析對象的作用域,如果一個對象的作用域在方法體內,那麽這個對象就沒有發生逃逸,沒有發生逃逸的對象可以進行棧上分配。
關於逃逸分析更深入的理解,可以參考這篇博客:https://blog.csdn.net/w372426096/article/details/80938788
JVM性能調優 第七章 內存分配策略