柚子快報(bào)激活碼778899分享:java JVM入門
柚子快報(bào)激活碼778899分享:java JVM入門
文章目錄
什么是程序計(jì)數(shù)器介紹下Java堆內(nèi)存結(jié)構(gòu)在Java7與8的區(qū)別什么是虛擬機(jī)棧垃圾回收是否涉及棧內(nèi)存棧內(nèi)存分配越大越好嗎方法內(nèi)的局部變量是否是線程安全的
什么情況下棧內(nèi)存溢出堆棧的區(qū)別是什么解釋下方法區(qū)介紹下運(yùn)行時(shí)常量池
什么是類加載器類加載器有那些什么是雙親委派模型、JVM為什么采用雙親委派
類裝載的執(zhí)行過(guò)程對(duì)象什么時(shí)候可以被垃圾器回收那些對(duì)象可以作為GC Root
垃圾回收算法有那些JVM的分代回收MinorGc、MixedGc、FullGc區(qū)別JVM垃圾回收器有那些概述G1垃圾回收器強(qiáng)軟弱虛JVM調(diào)優(yōu)參數(shù)可以在哪里設(shè)置參數(shù)值JVM調(diào)優(yōu)參數(shù)有那些JVM調(diào)優(yōu)的工具Java內(nèi)存泄漏如何排查CPU飆高排查方案OOM排查 (說(shuō)這個(gè)?。?/p>
什么是程序計(jì)數(shù)器
程序私有的,內(nèi)部保存的字節(jié)碼的行號(hào),用于記錄正在執(zhí)行的字節(jié)碼指令的地址。
介紹下Java堆
java堆就是線程共享的區(qū)域,主要用來(lái)保存對(duì)象實(shí)例、數(shù)組等,當(dāng)堆中沒(méi)有內(nèi)存空間可分配也無(wú)法擴(kuò)展的時(shí)候就會(huì)拋出OOM異常 組成:年輕代+老年代 年輕代被劃分為三部分,Eden區(qū)和兩個(gè)相同的Survior區(qū)(幸存者區(qū)) 老年代主要保存生命周期長(zhǎng)的對(duì)象
內(nèi)存結(jié)構(gòu)在Java7與8的區(qū)別
在java8之后將原有堆中的方法區(qū)/永久代(主要保存了類信息、常量、編譯后的代碼) 放在了本地內(nèi)存的元空間中,原因是避免OOM,放在內(nèi)存溢出
什么是虛擬機(jī)棧
每個(gè)線程運(yùn)行時(shí)所需要的內(nèi)存,被稱為虛擬機(jī)棧,特點(diǎn)是先進(jìn)后出 每個(gè)棧由多個(gè)棧幀組成,就是每次方法調(diào)用時(shí)所占用的內(nèi)存
垃圾回收是否涉及棧內(nèi)存
垃圾回收就是指堆內(nèi)存當(dāng)棧幀彈棧之后內(nèi)存就會(huì)釋放
棧內(nèi)存分配越大越好嗎
不是,默認(rèn)是1024k,棧幀過(guò)大會(huì)導(dǎo)致線程數(shù)變少,通常就是用默認(rèn)的
方法內(nèi)的局部變量是否是線程安全的
如果方法內(nèi)局部變量只作用于方法內(nèi),他是線程安全的但如果局部變量引用了對(duì)象,并逃離了方法的作用范圍,此時(shí)需要考慮線程安全
什么情況下棧內(nèi)存溢出
棧幀過(guò)多導(dǎo)致棧內(nèi)存溢出,典型問(wèn)題:遞歸棧幀過(guò)大導(dǎo)致棧內(nèi)存溢出(一般不會(huì)出現(xiàn),也沒(méi)有遇到過(guò))
堆棧的區(qū)別是什么
棧內(nèi)存一般用來(lái)存儲(chǔ)局部變量和方法調(diào)用的,堆內(nèi)存是用來(lái)存儲(chǔ)Java對(duì)象和數(shù)組的,堆會(huì)GC垃圾回收,棧不會(huì)棧內(nèi)存是線程私有的,堆內(nèi)存是線程共有的(需要考慮線程安全問(wèn)題)兩者拋出異常錯(cuò)誤也不同, 棧內(nèi)存不足是SOF、堆內(nèi)存不足是OOM
解釋下方法區(qū)
方法區(qū)Method Area 是各個(gè)線程共享的內(nèi)存區(qū)域,主要存儲(chǔ)類的信息、運(yùn)行時(shí)常量池
介紹下運(yùn)行時(shí)常量池
當(dāng)類被加載,它的常量池信息就會(huì)放入運(yùn)行時(shí)常量池,并把里面的符號(hào)地址變?yōu)檎鎸?shí)地址 常量池是可以看作是一張表,虛擬機(jī)指令根據(jù)這張常量表找到要執(zhí)行的類名、方法名等信息;
什么是類加載器
JVM只會(huì)運(yùn)行二進(jìn)制文件,類加載器的作用就是將字節(jié)碼文件加載到JVM中從而讓Java程序能夠啟動(dòng)
類加載器有那些
啟動(dòng)類加載器、擴(kuò)展類加載器、應(yīng)用類加載器、自定義類加載器
什么是雙親委派模型、JVM為什么采用雙親委派
雙親委派模型就是加載某一個(gè)類時(shí),先委托上一級(jí)的加載器進(jìn)行加載,如果上級(jí)加載器也有上級(jí),就會(huì)繼續(xù)向上委托,如果該類委托上級(jí)沒(méi)有被加載,子類加載器就會(huì)嘗試加載該類 至于JVM為什么采用雙親委派是因?yàn)楸苊饽硞€(gè)類被重復(fù)的加載,當(dāng)父類已經(jīng)加載后則無(wú)需重復(fù)加載,保證唯一性,也能夠保證類庫(kù)API不會(huì)被更改
類裝載的執(zhí)行過(guò)程
加載-驗(yàn)證-準(zhǔn)備-解析=初始化-使用-卸載
對(duì)象什么時(shí)候可以被垃圾器回收
如果一個(gè)或多個(gè)對(duì)象沒(méi)有任何的引用指向它,那么這個(gè)對(duì)象就會(huì)被定位為垃圾,就可能被垃圾回收器回收 定位垃圾的方式有兩種:
引用計(jì)數(shù)法(當(dāng)對(duì)象出現(xiàn)循環(huán)引用時(shí),會(huì)出現(xiàn)內(nèi)存泄漏風(fēng)險(xiǎn))可達(dá)性分析算法(現(xiàn)在虛擬機(jī)都采用的此方法) 掃描堆中的對(duì)象,看是否能夠沿著GC Root對(duì)象為起點(diǎn)的引用鏈找到該對(duì)象,如果不能找到就表示可以被回收
那些對(duì)象可以作為GC Root
虛擬機(jī)棧(棧幀中的本地變量表)中引用的對(duì)象方法區(qū)中類靜態(tài)屬性引用的對(duì)象方法區(qū)中常量引用的對(duì)象本地方法棧中JNI引用的對(duì)象 都指向堆中的一塊區(qū)域
垃圾回收算法有那些
標(biāo)記清除算法: 分為2個(gè)階段:標(biāo)記和清除 根據(jù)可達(dá)性分析算法得出得垃圾進(jìn)行標(biāo)記 對(duì)這些標(biāo)記可回收的內(nèi)容進(jìn)行垃圾回收 標(biāo)記和清除速度塊,但碎片化嚴(yán)重,內(nèi)存不連貫標(biāo)記整理算法 與標(biāo)記清除算法差不,將存活對(duì)象都向內(nèi)存另一端移動(dòng),然后清理邊界以外的垃圾,無(wú)碎片,但對(duì)象需要移動(dòng),效率較低復(fù)制算法 在垃圾對(duì)象多的情況下,效率比較高,并且清理后內(nèi)存無(wú)碎片化的,但是它需要分配2塊內(nèi)存空間,在同一時(shí)刻,只能使用一半,內(nèi)存使用率低
JVM的分代回收
首先將新創(chuàng)建的對(duì)象,都會(huì)分配到eden區(qū) 之后當(dāng)eden區(qū)內(nèi)存不足時(shí),標(biāo)記eden與from的存活對(duì)象,將存活的對(duì)象采用復(fù)制算法復(fù)制到to中,復(fù)制完畢清除eden和from內(nèi)存 經(jīng)過(guò)一段時(shí)間后eden的內(nèi)存又出現(xiàn)不足,就會(huì)標(biāo)記eden和to區(qū)域存活的對(duì)象,并復(fù)制到from區(qū) 當(dāng)幸存區(qū)對(duì)象被來(lái)回的回收多次之后,就會(huì)晉升到老年代(辛存區(qū)內(nèi)存不足或大對(duì)象會(huì)提取晉升)
堆的區(qū)域劃分
堆被劃分為兩份:新生代和老年代【1:2】對(duì)于新生代,內(nèi)部又被劃分為三個(gè)區(qū)域:eden伊甸園區(qū)和survivor幸存者區(qū)(分為from和to)【8:1:1】
MinorGc、MixedGc、FullGc區(qū)別
MinorGc:young Gc 發(fā)生在新生代的垃圾回收,暫停時(shí)間短(STW) MixedGc:新生代+老年代部分區(qū)域的垃圾回收,G1收集器特有 FullGc:新生代+老年代完整垃圾回收,暫停時(shí)間長(zhǎng)(STW),盡量避免
JVM垃圾回收器有那些
串行垃圾收集器:SerialGC、Serial Old GC并行垃圾收集器:Paraller Old GC、ParNew GCCMS(并發(fā))垃圾收集器:CMS GC作用在老年代G1垃圾收集器:作用在新生代和老年代
概述G1垃圾回收器
G1垃圾回收器應(yīng)用在新生代和老年代中,在JDK9之后垃圾回收器默認(rèn)使用G1, G1垃圾回收器劃分了多個(gè)區(qū)域,每個(gè)區(qū)域都可充當(dāng)eden、survivor、old、humongous,其中humongous存儲(chǔ)大對(duì)象的 G1垃圾回收器分為三個(gè)階段: 1.新生代回收STW 2.并發(fā)標(biāo)記,就是重新標(biāo)記STW 3.混合收集 采用復(fù)制算法,如果并發(fā)失敗,會(huì)觸發(fā)full GC
強(qiáng)軟弱虛
強(qiáng)引用: 只要能被GC Root找到就是強(qiáng)引用,平時(shí)new的也是強(qiáng)引用。強(qiáng)引用的對(duì)象,即使出現(xiàn)OOM也不會(huì)對(duì)該對(duì)象進(jìn)行回收,死都不收 軟引用: 需要用SoftReference類來(lái)實(shí)現(xiàn),軟引用在內(nèi)存夠用時(shí)就會(huì)保留,不夠用時(shí)就回收 弱引用: 需要用WeakReference類來(lái)實(shí)現(xiàn),只要垃圾回收機(jī)制運(yùn)行,不管JVM內(nèi)存是否足夠,都會(huì)回收 虛引用: 必須配合引用隊(duì)列聯(lián)合使用,被引用的對(duì)象回收時(shí),會(huì)被虛引用入隊(duì),由Reference Handler線程調(diào)用虛引用相關(guān)方法釋放直接內(nèi)存
JVM調(diào)優(yōu)參數(shù)可以在哪里設(shè)置參數(shù)值
Xms 堆的初始化大小 Xmx最大大小
war包部署在tomcat中設(shè)置 修改TOMCAT_HOME/bin/catalina.sh文件(111行:JAVA_OPTS=“-Xms512m -Xmx1024m”) jar包部署在啟動(dòng)參數(shù)設(shè)置 java -Xms512m -Xmx1024m -jar xxx.jar
JVM調(diào)優(yōu)參數(shù)有那些
設(shè)置堆空間的大小 -Xms堆初始化大小 -Xmx堆最大大小 默認(rèn)是物理內(nèi)存的1/4 為防止垃圾收集器在初始大小、最大大小之間收縮堆而產(chǎn)生額外的時(shí)間,通常設(shè)置成相同的值虛擬機(jī)棧的設(shè)置 每個(gè)線程默認(rèn)會(huì)開啟1M的內(nèi)存,用于存放棧幀、調(diào)用參數(shù)、局部變量等,工作中512k就夠用 -Xss 對(duì)每個(gè)Stack大小的調(diào)整年輕代中Eden區(qū)和兩個(gè)Survior區(qū)的大小比例 -XXSurvivorRation=8 #表示年輕代中分配比率:survivor:eden=2:8 默認(rèn)是8:1:1; 通過(guò)增大eden區(qū)的大小,來(lái)減少YGC發(fā)生的次數(shù),但在eden區(qū)滿的時(shí)候,由于占用的空間較大,導(dǎo)致釋放緩慢,STW時(shí)間較長(zhǎng)的,所以一般是不確定的,需要根據(jù)程序情況調(diào)優(yōu)年輕代晉升老年代閾值 -XX:MaxTenuringThreshold=threshoid 默認(rèn):15 (取值范圍:0~15)設(shè)置垃圾回收收集器 默認(rèn)是并發(fā)的垃圾回收器 -XX:+UseParallelGC -XX:+UseParallelOldGC 設(shè)置垃圾回收期 -XX:+UseG1GC
JVM調(diào)優(yōu)的工具
命令常用的是:
jps 查詢進(jìn)程 jstack 查看java進(jìn)程內(nèi)線程的堆棧信息 jmap 查看堆轉(zhuǎn)信息 jmap -heap 進(jìn)程id jmap -dump:format=b,file=指定路徑/xxx.hprof 進(jìn)程id (生成堆轉(zhuǎn)信息dump文件) jhat 堆轉(zhuǎn)儲(chǔ)快照分析工具 jstat JVM統(tǒng)計(jì)監(jiān)測(cè)工具,用來(lái)顯示垃圾回收信息、類加載信息、新生代統(tǒng)計(jì)信息等
使用可視化工具查看:VisualVM
Java內(nèi)存泄漏如何排查
出現(xiàn)內(nèi)存泄漏的有三個(gè)地方
JVM stacks虛擬機(jī)棧 StackOverFlowError方法區(qū)/元空間 OOM:MetaspaceHeap 堆 OOM:java heap space
內(nèi)存泄漏和內(nèi)存溢出都涉及到Java虛擬機(jī)(JVM)中的內(nèi)存管理,但它們是不同的概念。 內(nèi)存泄漏(Memory Leak): 內(nèi)存泄漏是指程序中分配的內(nèi)存空間在不再需要時(shí)沒(méi)有被釋放,導(dǎo)致該內(nèi)存無(wú)法被重新使用,最終耗盡可用內(nèi)存。 典型的內(nèi)存泄漏場(chǎng)景包括對(duì)象被持續(xù)引用而無(wú)法被垃圾回收器回收、緩存對(duì)象無(wú)限增長(zhǎng)、長(zhǎng)時(shí)間存在的監(jiān)聽器未被移除等。 內(nèi)存溢出(Memory Overflow): 內(nèi)存溢出是指程序在申請(qǐng)內(nèi)存空間時(shí),無(wú)法獲得足夠的內(nèi)存而導(dǎo)致無(wú)法繼續(xù)執(zhí)行。 典型的內(nèi)存溢出情況包括堆內(nèi)存溢出(Heap Overflow)和棧內(nèi)存溢出(Stack Overflow)。堆內(nèi)存溢出通常是由于創(chuàng)建了過(guò)多的對(duì)象而耗盡了堆內(nèi)存,而棧內(nèi)存溢出則是由于遞歸調(diào)用或者方法調(diào)用鏈過(guò)長(zhǎng)而耗盡了棧內(nèi)存。
1.通過(guò)jmap指令獲取堆內(nèi)存快照dump 2.VisualVM分析dump文件 3.通過(guò)查看堆轉(zhuǎn)儲(chǔ)信息的情況,定位內(nèi)存溢出問(wèn)題
CPU飆高排查方案
1.使用top命令查看占用CPU的情況,定位到那個(gè)進(jìn)程占用CPU較高 2.使用ps命令查看進(jìn)程中的線程信息 3.使用jstack命令查看進(jìn)程中那些線程出現(xiàn)問(wèn)題了,最后定位原代碼
OOM排查 (說(shuō)這個(gè)!)
工具:Jprofiler (老工具M(jìn)AT) 作用:分析Dump內(nèi)存文件,定位內(nèi)存泄漏;獲取堆的數(shù)據(jù);獲取大對(duì)象等 安裝:
1.安裝插件Plugins–>Jprofiler 2.官網(wǎng)下載Jprofiler軟件 無(wú)腦安裝(License key注冊(cè)碼需要獲?。?3.安裝完畢后–>Settings–>Tools–>Jprofiler 綁定軟件路徑(xxx\bin\jprofiler.exe)
測(cè)試代碼:
//在Configurations--Application--VM options設(shè)置參數(shù)
//-Xms 設(shè)置初始化內(nèi)存分配大小 默認(rèn) 1/64
//-Xmx 設(shè)置最大分配內(nèi)存 默認(rèn)1/4
//-XX:+PrintGCDetails 打印GC垃圾回收信息
//-Xms1m -Xmx8m -XX:+HeapDumpOnOutOfMemoryError OOM完整參數(shù)設(shè)置 Heap堆 Dump On條件 OutOfMemoryError既OOM錯(cuò)誤 就Dump文件
public class Demo{
byte[] array = new byte[1*1024*1024];//1m
public static void main(String[] args){
ArrayList
int count = 0;
try{
while(true){
list.add(new Demo());
count = count + 1;
}
}catch(Error e){
System.out.println("count:"+count);
e.printStackTrace();
}
//獲取最大內(nèi)存
//long max = Runtime.getRuntime().maxMemory(); //字節(jié)
//獲取JVM的初始化總內(nèi)存
//long total = Runtime.getRuntime().totalMemory();
//轉(zhuǎn)MB --max/(DOUBLE)1024/1024
}
}
最后通過(guò)Jprofiler軟件分析Dump文件
柚子快報(bào)激活碼778899分享:java JVM入門
精彩內(nèi)容
本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點(diǎn)和立場(chǎng)。
轉(zhuǎn)載請(qǐng)注明,如有侵權(quán),聯(lián)系刪除。