柚子快報邀請碼778899分享:JVM初探
柚子快報邀請碼778899分享:JVM初探
JVM的位置
JVM體系架構(gòu)
類加載器
類加載器收到類加載的請求將這個請求委托給父類加載器,一直向上委托,直到啟動類加載器啟動類加載器檢查是否能加載這個類,能加載就結(jié)束,使用當(dāng)前的加載器,否則就拋出異常,通知子加載器進(jìn)行加載重復(fù)步驟3若都沒找到拋出ClassNotFind異常
雙親委派機(jī)制:保護(hù)安全 (APP -> EXC -> BOOT) eg.如自己創(chuàng)建了一個和jdk庫中類名相同的類,會一直向上找,最終在最上層運(yùn)行
Native
凡是帶了native關(guān)鍵字的,說明java的作用范圍達(dá)不到了,會去調(diào)用底層C語言的庫! 會進(jìn)入本地方法棧,調(diào)用本地方法接口(JNI)
例如:new Tread().start() 源碼中的 start0()方法。 private native void start0();
使用場景:Java驅(qū)動打印機(jī),主要用于調(diào)用硬件,一般用不到
程序計數(shù)器(PC計數(shù)器)
一個線程一個虛擬機(jī)棧,每個線程私有的,就是一個指針,指向方法區(qū)中的方法字節(jié)碼(用來存儲指向一條指令的地址,也即將要執(zhí)行的指令代碼),占內(nèi)存非常小可以忽略不計
方法區(qū)
方法區(qū)是被所有線程共享靜態(tài)變量、常量、類信息(構(gòu)造方法、接口定義)、運(yùn)行時的常量池在方法區(qū)中,但是實例變量存在堆中。static、final、Class、常量池
棧
虛擬機(jī)棧又叫棧內(nèi)存,主管程序的運(yùn)行,生命周期和線程同步 一個線程一個虛擬機(jī)棧,線程結(jié)束,棧內(nèi)存也就釋放,對于棧來說不存在垃圾回收問題 主要存放 8大基本類型 + 對象引用地址 + 實例的方法
棧運(yùn)行原理:棧幀 棧滿了:StackOverflowError(遞歸循環(huán)調(diào)用)
棧、堆、方法區(qū)的調(diào)用關(guān)系:
堆
Heap。一個JVM只有一個堆內(nèi)存,堆內(nèi)存的大小是可以調(diào)節(jié)的。
類加載器讀取了類文件后,一般會把類、方法、常量、變量、保存我們所有引用類型的真是對象放在堆中
JDK8以前,堆中分為三個區(qū)域
新生區(qū)
類:誕生和成長的地方,甚至死亡所有的對象都是在伊甸園區(qū)被new出來的幸存者區(qū)(有0和1區(qū)) 老年區(qū)
經(jīng)過GC之后仍然存活的對象 永久區(qū) 這個區(qū)域常駐內(nèi)存,用來存放JDK自身攜帶的Class對象、Interface元數(shù)據(jù),存儲的是Java運(yùn)行時的環(huán)境。這個區(qū)域不存在垃圾回收。關(guān)閉虛擬機(jī)就會釋放這個區(qū)域的內(nèi)存。 以下情況會出現(xiàn)OOM:大量動態(tài)生成的反射類不斷被加載、Tomcat部署了太多應(yīng)用、一個啟動類加載了大量第三方Jar包
jdk1.6之前:永久代,常量池在方法區(qū)jdk1.7:永久代,常量池在堆中jdk1.8之后:元空間,常量池在元空間中。
GC垃圾回收主要在新生區(qū)和老年區(qū)
新生區(qū)中的伊甸園區(qū)滿了之后會發(fā)生輕量級GC
輕GC一次后未回收的對象在幸存區(qū),達(dá)到15或20次之后到達(dá)養(yǎng)老區(qū) 老年區(qū)滿了之后會發(fā)生重量級GC(Full GC)
假設(shè)內(nèi)存滿了,會報錯OOM。(例如String一直+=)
堆內(nèi)存OOM解決:
嘗試擴(kuò)大堆內(nèi)存看結(jié)果:在Edit Configuration界面VM options參數(shù)中填寫: -Xms1024m -Xmx1024m。(默認(rèn)情況下分配的總內(nèi)存是電腦內(nèi)存的1/4,而初始化的內(nèi)存是1/64)分析內(nèi)存,看哪個地方出現(xiàn)了問題(一般是內(nèi)存泄露)使用JProfiler
新生區(qū)的內(nèi)存大小+老年區(qū)的內(nèi)存大小=總內(nèi)存大小,說明了元空間邏輯上存在物理上不存在。
使用JProfiler工具分析OOM原因
idea下載JProfiler插件,百度下載JProfiler軟件
在Edit Configuration界面VM options參數(shù)中填寫: -Xms1m -Xmx8m -Xx:+HeapDumpOnOutOfMemoryError) 其中(OutOfMemoryError)可替換,-Xms設(shè)置初始化內(nèi)存分配大小, -Xmx設(shè)置最大分配內(nèi)存,-Xx:+PrintGCDetails打印GC垃圾回收具體信息,-Xx:+HeapDumpOnOutOfMemoryError打印OOM Dump信息
運(yùn)行后會在src同級目錄自動生成 .hprof文件,雙擊打開后可在Biggest Objects中查看哪些類占用較大 在左側(cè)Heap walker中可查看哪行代碼出了問題
GC垃圾回收算法
只在堆中進(jìn)行GC,
引用計數(shù)法(基本不會使用) 復(fù)制算法
from和to區(qū)是隨時變換的,但to區(qū)一定是空的。 將幸存區(qū)from中的對象全部移動到to中。
好處:沒有內(nèi)存的碎片壞處:浪費(fèi)了內(nèi)存空間:永遠(yuǎn)都會有一塊是空的(to區(qū))。當(dāng)from全部存活時,復(fù)制算法將會造成非常大的浪費(fèi)。使用場景:對象存活度較低的時候(新生區(qū))
標(biāo)記清除算法 缺點:兩次掃描,嚴(yán)重浪費(fèi)時間,會產(chǎn)生內(nèi)存碎片 有點:不需要額外空間 標(biāo)記整理(標(biāo)記壓縮)
在標(biāo)記清除的步驟中多加了一步掃描:整理
標(biāo)記清除整理(標(biāo)記清除壓縮算法)
在標(biāo)記清除5次后,再進(jìn)行整理
總結(jié):
內(nèi)存效率(時間復(fù)雜度):復(fù)制算法 > 標(biāo)記清除算法 > 標(biāo)記整理(壓縮)算法 內(nèi)存整齊度:復(fù)制算法 = 標(biāo)記整理(壓縮)算法 > 標(biāo)記清除算法 內(nèi)存利用率:標(biāo)記清除算法 = 標(biāo)記整理(壓縮)算法 > 復(fù)制算法
沒有最優(yōu)的算法,只有最合適的算法------>GC分代收集算法
GC分代收集算法: 年輕代:存活率低,使用復(fù)制算法 老年代:區(qū)域大、存活率高:標(biāo)記清楚(內(nèi)存碎片不是太多) + 標(biāo)記整理混合實現(xiàn)
輕GC(Minor GC)和重GC(Full GC)
Minor GC
當(dāng)新對象去伊甸園區(qū)(Eden)申請內(nèi)存失敗的時候,就會進(jìn)行Minor GC,對伊甸園區(qū)(Eden)回收非存活對象,而沒有被回收的對象,會進(jìn)入幸存區(qū)(Survivor),這種GC只發(fā)生在伊甸園區(qū)(Eden),不會影響到老年區(qū)。因為新對象分配內(nèi)存大部分都在伊甸園區(qū)(Eden),所以伊甸園區(qū)(Eden)GC比較頻繁。
注意:在GC之后,還存活的對象,進(jìn)入幸存區(qū)(Survivor),誰空誰是to,可以交換位置,當(dāng)一個對象經(jīng)歷了15次GC(可以配置次數(shù):-XX:+MaxTenuringThreshold=15),還存活,就進(jìn)入老年區(qū)。
Full GC
清理整個堆,因為Full GC需要對整個堆進(jìn)行回收,所以比Minor GC慢,因為我們要盡可能的減少Full GC的次數(shù)。我們所說的JVM調(diào)優(yōu),很大一部分就是對Full GC的優(yōu)化。
以下情況會造成 Full GC:
老年區(qū)滿了:年輕區(qū)的對象轉(zhuǎn)入或創(chuàng)建大對象才會滿。 持久區(qū)滿了(jdk7及之前版本) 方法區(qū)滿了(jdk8及之后版本):系統(tǒng)中要加載的類過多。 System.gc() 被顯示調(diào)用 通過Minor GC后進(jìn)入老年代的平均大小大于老年代的可用內(nèi)存:第一次Minor GC之后,有2MB的對象轉(zhuǎn)入老年區(qū),然后在下一次Minor GC的時候就會判斷老年區(qū)的空間是否有2MB,如果沒有就進(jìn)行Full GC。
拓展
JMM
什么是JMM Java Memory Model :Java內(nèi)存模型它干嘛的? 緩存一致性協(xié)議,用于定義數(shù)據(jù)讀寫的規(guī)則(遵守) JMM中定義了線程工作內(nèi)存與主內(nèi)存之間的抽象關(guān)系:線程之間的共享變量存儲在主內(nèi)存(Main Memory)中,每個線程都有一個私有的本地內(nèi)存(Local Memory)
解決共享對象可見性的問題:volatile
柚子快報邀請碼778899分享:JVM初探
精彩文章
本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點和立場。
轉(zhuǎn)載請注明,如有侵權(quán),聯(lián)系刪除。