一份关于jvm内存调优及原理的学习笔记
JVM
?
一.虛擬機的基本結(jié)構(gòu)
?
1.jvm整體架構(gòu)
?
?
類加載子系統(tǒng):負責(zé)從文件系統(tǒng)或者網(wǎng)絡(luò)中加載class信息,存入方法區(qū)中。
方法區(qū)(Perm):存放加載后的class信息,包括靜態(tài)方法,jdk1.6以前包含了常量池。
參數(shù):-XX:PermSize初始值? -XX:MaxPermSize最大值
?
Java堆(Heap):java工程的主要內(nèi)存工作區(qū)域,所有線程共享,jdk1.7以后包含了常量池。參數(shù): -Xms初始值???? -Xmx最大值
?
直接內(nèi)存:java堆外,直接向系統(tǒng)申請的內(nèi)存區(qū)間,允許NIO庫使用。申請空間慢,讀寫快。默認下最大可用空間等于堆的最大可用空間。在server模式下,讀寫速度是堆的10倍。
參數(shù):-XX:MaxDirectMemorySize 最大值
?
垃圾回收器:
?
Java棧:線程私有,用于存放局部變量,方法參數(shù),同時和java方法的調(diào)用返回密切相關(guān)。
參數(shù):-Xss最大值
?
本地方法棧:和java棧類似,主要用于本地方法調(diào)用。
PC寄存器:線程私有
執(zhí)行引擎:
?
?
Java [-options] class [args...]
其中-options是java虛擬機的啟動參數(shù),args是傳遞給main方法的參數(shù)、
?
?
2.java堆
根據(jù)垃圾回收機制的不同,java堆有可能擁有不同的結(jié)構(gòu),常見的java堆分為新生代和老年代。其中新生代存放剛創(chuàng)建的對象及年齡不大的對象,老年帶存放著在新生代中經(jīng)歷過多次回收后還存在的對象。
?
?
?
對象晉升過程:
新生代分為eden區(qū)s0,s1區(qū)(from,to)。多數(shù)情況下對象首先分配在eden區(qū),在一次新生代回收后,存活下來的對象存入s0或s1區(qū)。每經(jīng)過一次新生代的回收,對象的年齡加1。默認情況下年齡達到15的對象將晉升至老年代。如果在第一次回收的時候,存活的對象大于s0(s1)空間,將直接晉升至老年代,如果在為對象第一次分配空間時,對象空間大于eden空間的話,對象也直接分配到老年代。
?
?
3.java棧
Java棧和數(shù)據(jù)結(jié)構(gòu)中的棧有著類似的含義,先進后出,只支持入棧和出棧操作。Java棧中保存的只要內(nèi)容是棧幀,每一次進行函數(shù)調(diào)用,都會有一個對應(yīng)的棧幀被壓入棧中,函數(shù)調(diào)用結(jié)束,都會有一個棧幀被彈出棧。
?
?
棧幀
每一個棧幀中包含局部變量表,操作數(shù)棧和幀數(shù)據(jù)區(qū)。
棧上分配
棧上分配的基本思想,是將線程私有的對象,打散分配到棧上,分配在棧上的函數(shù)調(diào)用結(jié)束后對象會自行銷毀,不需要垃圾回收接入,從而提升性能。對于大量的零散小對象,棧上分配提供了一種很好的對象分配優(yōu)化策略,但由于和堆空間相比,棧空間較小,因此大對象無法也不適合在棧上分配
棧上分配依賴逃逸分析和標(biāo)量替換的實現(xiàn),同時必須在server模式下才能啟用。參數(shù)-XX:+DoEscapeAnalysis啟用逃逸分析???? -XX:+EliminateAllocations開啟標(biāo)量替換(默認打開).
例:-server -Xms 100m -Xmx 100m -XX:+DoEscapeAnalysis -XX:+EliminateAllocations
?
?
二.Jvm常用參數(shù)
?
1.GC參數(shù)
-XX:+PrintGC??? 每次觸發(fā)GC的時候打印相關(guān)日志
-XX:+PrintGCDetails??? 更詳細的GC日志
-XX:+PrintHeapAtGC??? 每次GC時打印堆的詳細詳細信息
-XX:+PrintGCApplicationConcurrentTime??? 打印應(yīng)用程序執(zhí)行時間
-XX:+PrintGCApplicationAtoppedTime??? 打印應(yīng)用程序由GC引起的停頓時間
-XX:+PrintReferenceGC??? 跟蹤系統(tǒng)內(nèi)的軟引用,弱引用,虛引用和finallize隊列。
?
?
1.類跟蹤
-verbose:class??? 跟蹤類的加載和卸載
-XX:+TraceClassLoading??? 單獨跟蹤類加載
-XX:+TraceClassUnloading??? 單獨跟蹤類卸載
-XX:+PrintClassHistogram??? 查看運行時類的分布情況,使用時在控制臺按ctrl+break
?
?
2.系統(tǒng)參數(shù)查看
-XX:+PrintVMOptions?????? 運行時,打印jvm接受的命令行顯式參數(shù)
-XX:+PrintCommandLineFlags??? 打印傳遞jvm的顯式和隱式參數(shù)
-XX:+PrintFlagsFinal??? 打印所有系統(tǒng)參數(shù)值
?
?
3.堆
-Xms??? 堆初始值
-Xmx??? 堆最大可用值
-Xmn??? 新生代大小,一般設(shè)為整個堆的1/3到1/4左右
-XX:SurvivorRatio??? 設(shè)置新生代中eden區(qū)和from/to空間的比例關(guān)系n/1
-XX:NewRatio??? 設(shè)置老年代與新生代的比
?
想要合理的分配堆內(nèi)存,需要了解對象的晉升過程,可以參照上面介紹堆空間架構(gòu)時,對對象晉升過程的描述。
?
?
基本策略:堆的不同分布情況,對系統(tǒng)會產(chǎn)生一定的影響。盡可能將對象預(yù)留在新生代,減少老年代GC的次數(shù)(通常老年回收起來比較慢)。實際工作中,通常將堆的初始值和最大值設(shè)置相等,這樣可以減少程序運行時進行的垃圾回收次數(shù)和空間擴展,從而提高程序性能。
?
4.非堆
-XX:PermSize?? 方法區(qū)(永久區(qū))初始值
-XX:MaxPermSize??? 方法區(qū)(永久區(qū))最大值
-Xss??? 設(shè)置棧空間大小
-XX:MaxDirectMemorySize??? 直接內(nèi)存最大可用空間,設(shè)置不當(dāng)可能導(dǎo)致系統(tǒng)OOM
?
5.虛擬機工作模式
-client??? 默認工作模式
-server??? server工作模式,啟動虛擬機時需要顯式指定
與client模式相比,server模式啟動較慢,會嘗試搜集更多的系統(tǒng)性能信息,使用更復(fù)雜的優(yōu)化算法對程序進行優(yōu)化,server模式下系統(tǒng)完全啟動并進入穩(wěn)定期后,執(zhí)行速度遠遠快于client模式,適合長期后臺運行的系統(tǒng)。Client模式更適合運行時間不長,又追求啟動速度的客戶端程序。
?
?
三.Jvm性能監(jiān)控工具
1.JConsole
內(nèi)存監(jiān)控,線程監(jiān)控,類加載情況,虛擬機信息
2.Visual VM
線程dump和分析,性能分析,內(nèi)存快照分析,BTrace
3.Mission Control
MBean服務(wù)器,飛行記錄器
?
四.分析java堆
1.常見的內(nèi)存溢出原因及解決思路
(1)堆溢出:設(shè)置-Xmx調(diào)整最大可用堆空間
?
(2)直接內(nèi)存溢出:可能是系統(tǒng)內(nèi)存空間不足,同時沒達到參數(shù)默認的上限,沒有觸發(fā)GC導(dǎo)致OOM,解決方法是通過-XX:MaxDirectMemorySize 來限制最大內(nèi)存。
?
(3)過多線程導(dǎo)致OOM:由于每開啟一個線程都會給這個線程分配一個棧,因此當(dāng)線程數(shù)達到一定程度,系統(tǒng)空間不足的時候就會內(nèi)存溢出,可以嘗試減少堆空間,或者可以通過設(shè)置參數(shù)-Xss限制每個棧的大小。
?
(4)永久區(qū)溢出:系統(tǒng)加載的類過多,導(dǎo)致永久區(qū)溢出,通過-XX:MaxPermSize來設(shè)置永久區(qū)最大可用空間。
?
(5)GC效率低下引起的OOM:GC是內(nèi)存回收的關(guān)鍵,回收效率低很有可能引起內(nèi)存溢出,可以通過合理的分配堆(包括新生代和老年代)空間去解決。
?
?
2.String造成的內(nèi)存泄漏
內(nèi)存泄漏是指,不再使用的對象占據(jù)內(nèi)存不釋放,導(dǎo)致可用內(nèi)存不斷減小,最終引起內(nèi)存泄漏。在Java1.6中String.subString()方法就存在這樣的問題。
SubString中新生成的對象并沒有從value中獲取自己需要的那部分,而是直接簡單的使用了相同的引用,只是修改了offset和count,以此來確定新的String對象的值。當(dāng)原始字符串還在用的時候這種情況是沒有問題的,并且共用value還節(jié)省了部分的空間,但是一旦原始字符串被回收,value中多余的部分就造成了空間浪費。
?
3.淺堆和深堆
淺堆:是指一個對象本身所消耗的內(nèi)存,不包括其內(nèi)部引用的對象的大小。
深堆:是指對象的保留集中所有對象淺堆的大小之和。
保留集:是指當(dāng)對象A被垃圾回收后,可以釋放的所有對象的集合(包括A本身),通俗的講就是,僅被對象A所持有的對象的集合。
?
4.OQL查詢語句
類似于sql語法的查詢語句,可以在堆中進行對象的查找和篩選。
......
?
?
轉(zhuǎn)載于:https://www.cnblogs.com/RUN-TIME/p/5445115.html
總結(jié)
以上是生活随笔為你收集整理的一份关于jvm内存调优及原理的学习笔记的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 轻松自动化---selenium-web
- 下一篇: 【原】a.class与a .class的