JVM学习初整理
JVM
內(nèi)存結(jié)構(gòu)(運行時數(shù)據(jù)區(qū)):堆(Heap),方法區(qū)(Method area),棧(本地方法棧(Native Method Stacks),虛擬機(jī)方法棧(Java ?Virtual Machine Stacks)),程序計數(shù)器(The pc Register)
堆:java虛擬機(jī)所管理的內(nèi)存中最大的一塊;在虛擬機(jī)啟動時創(chuàng)建,被所有線程共享,java對象實例及數(shù)組都在堆上分配
方法區(qū):Java虛擬機(jī)規(guī)范把方法區(qū)描述為堆的一個邏輯部分,別名Non-Heap,目的是與java堆區(qū)分開來,在java虛擬機(jī)啟動時創(chuàng)建,被所有線程共享;用于存儲已被虛擬機(jī)加載的類信息,常量,靜態(tài)變量,即時編譯后的代碼等數(shù)據(jù);當(dāng)方法區(qū)無法滿足內(nèi)存要求時拋出OutOfMemoryError異常
虛擬機(jī)棧:是一個線程執(zhí)行的區(qū)域,保存著一個線程中方法的調(diào)用狀態(tài);
? ? ? ? ? ? ? 1:一個JAVA線程的運行狀態(tài)由一個虛擬機(jī)棧保存,所以虛擬機(jī)棧是線程私有的,隨著線程的創(chuàng)建而創(chuàng)建
? ? ? ? ? ? ? 2:每一個被線程執(zhí)行的方法為該棧中的棧幀,即每個方法對應(yīng)一個棧幀;調(diào)用一個方法就會向棧中壓入一個棧幀,一個方法調(diào)用完成,就會把該棧幀從棧中彈出(FILO先壓入的棧幀后彈出)
程序計數(shù)器:線程的執(zhí)行權(quán)由CPU時間分片輪換調(diào)度,當(dāng)一個線程執(zhí)行過程中失去了執(zhí)行權(quán)時由程序計數(shù)器記錄當(dāng)前線程執(zhí)行的位置,待線程再次獲得執(zhí)行權(quán)時由程序計數(shù)器記錄的位置處開始執(zhí)行
? ? ? ? ? ? ? ?1:如果線程正在執(zhí)行的是JAVA方法,則計數(shù)器記錄的是正在執(zhí)行的虛擬機(jī)字節(jié)碼指令的地址
? ? ? ? ? ? ? ?2:如果線程正在執(zhí)行的是native方法,則這個計數(shù)器為空
本地方法棧:如果線程執(zhí)行的是native方法,這些方法就會在本地方法棧中執(zhí)行;如果在JAVA方法中調(diào)用native方法,則以動態(tài)鏈接的方式執(zhí)行調(diào)用
內(nèi)存結(jié)構(gòu)(概念):老年代(old),新生代(Eden,survive0,survice1)
垃圾回收(GC):
? ? Eden:1:在JAVA對象的頭部(markWord)中會存儲當(dāng)前的對象GC次數(shù),當(dāng)一個對象GC次數(shù)大于18時會將此對象從新生代轉(zhuǎn)移到老年代
? ? ? ? ? ? ? ? 2:當(dāng)有較大的對象進(jìn)入Eden區(qū)時,首先會將Eden存在的不連續(xù)空間的對象轉(zhuǎn)移到survive0區(qū);當(dāng)survive0區(qū)中的對象總內(nèi)存超過survive0區(qū)的一半時,將survive0區(qū)中對象復(fù)制到survive1區(qū)中以便在survive0區(qū)中空出連續(xù)的完整空間
? ? ? ? ? ? ? ? 3:當(dāng)占有超過Eden區(qū)內(nèi)存一半的對象時,會直接存放到老年代
? 什么時候會進(jìn)行垃圾回收:
? ? ? ? ? ? ? ? ?1:當(dāng)Eden區(qū)或S區(qū)內(nèi)存不夠用了
? ? ? ? ? ? ? ? ?2:老年代空間不夠用了
? ? ? ? ? ? ? ? ?3:方法區(qū)空間不夠用了
? ? ? ? ? ? ? ? 4:System.gc()
垃圾回收算法:標(biāo)記-清除,標(biāo)記復(fù)制
? ?可達(dá)性分析算法:通過GC Root對象(能作為GC Root:類加載器,Thread,虛擬機(jī)棧的本地變量表,static成員,常量引用,本地方法棧的變量等)開始向下尋找,看某個對象是否可達(dá),不可達(dá)的對象標(biāo)記回收
標(biāo)記-清除(Mark ?Sweep)
? ? 標(biāo)記:找出內(nèi)存中需要回收的對象,并且把它們標(biāo)記出來。此時堆中的所有對象都要被掃描一遍,才能確定需要被回收的對象,比較耗時。
? ? 清除: 清除掉被標(biāo)記需要回收的對象,釋放出對應(yīng)的內(nèi)存空間。
? ? 缺點: ?標(biāo)記清除之后會產(chǎn)生大量不連續(xù)的內(nèi)存碎片,空間碎片太多可能會導(dǎo)致以后在程序運行過程中需要分配較大對象時,無法找到足夠的連續(xù)內(nèi)存而不得不提前觸發(fā)另一次垃圾收集動作。
標(biāo)記-復(fù)制(Mark Copying)
? ? ? 將內(nèi)存劃分為兩塊相等的區(qū)域,每次只使用其中一塊,當(dāng)其中一塊使用完了,就將還存活的對象復(fù)制到另外一塊內(nèi)存上,然后把已使用過的內(nèi)存空間一次清除掉。
? ? ?缺點:空間利用率降低
標(biāo)記-整理(Mark Compact)
? ? ?標(biāo)記過程與“標(biāo)記清除算法”一致,但后續(xù)步驟不是直接對可回收對象進(jìn)行清理,而是讓存活對象都向一端移動,然后直接清理掉端邊界以外的內(nèi)存。 相較于“標(biāo)記復(fù)制算法”來說少了一個“保留區(qū)”。
?Young區(qū):復(fù)制算法(對象在被分配之后,可能生命周期比較短,Young區(qū)復(fù)制率較高)
?Old區(qū):標(biāo)記清除或整理(Old區(qū)對象存活時間比較長,復(fù)制來復(fù)制去沒有必要,不如做個標(biāo)記再整理)
?垃圾收集器分類:
? ? ? ? 串行收集器:Serial、Serial Old
? ? ? ? 只能有一個垃圾回收線程執(zhí)行,用戶線程暫停;適用于內(nèi)存比較小的嵌入式設(shè)備
? ? ? ? 并行收集器(吞吐量優(yōu)先):Parallel Scanvenge、 Parallel Old
? ? ? ? ?多條垃圾回收線程并行工作,但此時用戶線程仍然處理等待狀態(tài);適用于科學(xué)計算,后臺處理等交互場景
? ? ? ? 并發(fā)收集器(停頓時間優(yōu)先):CMS、G!
? ? ? ? 用戶線程和垃圾收集線程同時執(zhí)行(可能是交替執(zhí)行),垃圾收集線程在執(zhí)行的時候不會停頓用戶線程的運行;適用于相對時間有要求的場景,比如Web
內(nèi)存泄漏與內(nèi)存溢出的區(qū)別
內(nèi)存泄漏是指不再使用的對象無法得到及時的回收,持續(xù)占用空間,從而造成內(nèi)存空間的浪費。
內(nèi)存泄漏很容易導(dǎo)致內(nèi)存溢出,但內(nèi)存溢出不一定是內(nèi)存泄漏導(dǎo)致的
JVM查看參數(shù)
java -XX:+PrintFlagsFinal -version > flags.txt
常用命令:
jps:查看java進(jìn)程
jinfo:實時查看和調(diào)整JVM配置參數(shù)
? ? ? ? ? 1:查看某個java進(jìn)程某個屬性值: jinfo -flag name PID
? ? ? ? ? 2:修改某個屬性值:jinfo -flag [+ | -] PID? ? /? ? ?jinfo -flag <name>=<value> PID
? ? ? ? ? 3:查看曾經(jīng)賦過值的一些參數(shù)? jinfo -flags PID
? jstat:查看虛擬機(jī)性能統(tǒng)計信息
? ? ? ? ? 1:jstat -class PID 1000 10? ?查看某個java進(jìn)程的類裝載信息? 沒1000ms輸出一次共輸出10次
? ? ? ? ? 2:jstat -gc PID 1000 10 查看垃圾收集信息
jstack:查看線程堆棧信息? ? jstack PID? 檢測死鎖,? 或者使用jconsole工具也可檢測死鎖
jmap:生成堆轉(zhuǎn)儲快照
? ? ? ? ? ?1:jmap -heap PID 打印堆內(nèi)存相關(guān)信息
? ? ? ? ? ?2:jmap -dump:format=b,file=heap.hprof PID? dump出堆內(nèi)存相關(guān)信息
? ? ? ? ? ?3:-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=heap.hprof? 內(nèi)存溢出時自動dump堆內(nèi)存相關(guān)信息
常用參數(shù)含義
總結(jié)
- 上一篇: 神策数据新 DEMO 上线,助力零售行业
- 下一篇: h3c ip和mac地址绑定