1、JVM 整體組成
JVM 整體組成可分為以下四個(gè)部分:
- 類加載器(ClassLoader)
- 運(yùn)行時(shí)數(shù)據(jù)區(qū)(Runtime Data Area)
- 執(zhí)行引擎(Execution Engine)
- 本地庫(kù)接口(Native Interface)
2、JVM內(nèi)存分哪幾個(gè)區(qū),每個(gè)區(qū)的作用是什么?
方法區(qū):
- 有時(shí)候也成為永久代此衅,在該區(qū)內(nèi)很少發(fā)生垃圾回收,但是并不代表不發(fā)生GC亭螟,在這里進(jìn)行的GC主要是對(duì)方法區(qū)里的常量池和對(duì)類型的卸載
- 方法區(qū)主要用來(lái)存儲(chǔ)已被虛擬機(jī)加載的類的信息挡鞍、常量、靜態(tài)變量和即時(shí)編譯器編譯后的代碼等數(shù)據(jù)预烙。
- 該區(qū)域是被線程共享的墨微。
- 方法區(qū)里有一個(gè)運(yùn)行時(shí)常量池,用于存放靜態(tài)編譯產(chǎn)生的字面量和符號(hào)引用扁掸。該常量池具有動(dòng)態(tài)性欢嘿,也就是說(shuō)常量并不一定是編譯時(shí)確定,運(yùn)行時(shí)生成的常量也會(huì)存在這個(gè)常量池中也糊。
虛擬機(jī)棧:
- 虛擬機(jī)棧也就是我們平常所稱的棧內(nèi)存,它為java方法服務(wù)炼蹦,每個(gè)方法在執(zhí)行的時(shí)候都會(huì)創(chuàng)建一個(gè)棧幀,用于存儲(chǔ)局部變量表狸剃、操作數(shù)棧掐隐、動(dòng)態(tài)鏈接和方法出口等信息。
- 虛擬機(jī)棧是線程私有的,它的生命周期與線程相同虑省。
- 局部變量表里存儲(chǔ)的是基本數(shù)據(jù)類型匿刮、returnAddress類型(指向一條字節(jié)碼指令的地址)和對(duì)象引用,這個(gè)對(duì)象引用有可能是指向?qū)ο笃鹗嫉刂返囊粋€(gè)指針探颈,也有可能是代表對(duì)象的句柄或者與對(duì)象相關(guān)聯(lián)的位置熟丸。局部變量所需的內(nèi)存空間在編譯器間確定
- 操作數(shù)棧的作用主要用來(lái)存儲(chǔ)運(yùn)算結(jié)果以及運(yùn)算的操作數(shù),它不同于局部變量表通過(guò)索引來(lái)訪問(wèn)伪节,而是壓棧和出棧的方式
- 每個(gè)棧幀都包含一個(gè)指向運(yùn)行時(shí)常量池中該棧幀所屬方法的引用光羞,持有這個(gè)引用是為了支持方法調(diào)用過(guò)程中的動(dòng)態(tài)連接.動(dòng)態(tài)鏈接就是將常量池中的符號(hào)引用在運(yùn)行期轉(zhuǎn)化為直接引用。
本地方法棧
本地方法棧和虛擬機(jī)棧類似怀大,只不過(guò)本地方法棧為Native方法服務(wù)纱兑。
堆
java堆是所有線程所共享的一塊內(nèi)存,在虛擬機(jī)啟動(dòng)時(shí)創(chuàng)建化借,幾乎所有的對(duì)象實(shí)例都在這里創(chuàng)建潜慎,因此該區(qū)域經(jīng)常發(fā)生垃圾回收操作。
程序計(jì)數(shù)器
內(nèi)存空間小蓖康,字節(jié)碼解釋器工作時(shí)通過(guò)改變這個(gè)計(jì)數(shù)值可以選取下一條需要執(zhí)行的字節(jié)碼指令铐炫,分支、循環(huán)蒜焊、跳轉(zhuǎn)倒信、異常處理和線程恢復(fù)等功能都需要依賴這個(gè)計(jì)數(shù)器完成。該內(nèi)存區(qū)域是唯一一個(gè)java虛擬機(jī)規(guī)范沒(méi)有規(guī)定任何OOM情況的區(qū)域山涡。
3堤结、什么情況下會(huì)發(fā)生棧內(nèi)存溢出唆迁?
- 棧是線程私有的鸭丛,棧的生命周期和線程一樣,每個(gè)方法在執(zhí)行的時(shí)候就會(huì)創(chuàng)建一個(gè)棧幀唐责,它包含局部變量表鳞溉、操作數(shù)棧、動(dòng)態(tài)鏈接鼠哥、方法出口等信息熟菲,局部變量表又包括基本數(shù)據(jù)類型和對(duì)象的引用;
- 當(dāng)線程請(qǐng)求的棧深度超過(guò)了虛擬機(jī)允許的最大深度時(shí)朴恳,會(huì)拋出StackOverFlowError異常抄罕,方法遞歸調(diào)用肯可能會(huì)出現(xiàn)該問(wèn)題
- 調(diào)整參數(shù)-xss去調(diào)整jvm棧的大小
4、如和判斷一個(gè)對(duì)象是否存活?(或者GC對(duì)象的判定方法)
判斷一個(gè)對(duì)象是否存活有兩種方法:
引用計(jì)數(shù)法
所謂引用計(jì)數(shù)法就是給每一個(gè)對(duì)象設(shè)置一個(gè)引用計(jì)數(shù)器于颖,每當(dāng)有一個(gè)地方引用這個(gè)對(duì)象時(shí)呆贿,就將計(jì)數(shù)器加一,引用失效時(shí),計(jì)數(shù)器就減一做入。當(dāng)一個(gè)對(duì)象的引用計(jì)數(shù)器為零時(shí)冒晰,說(shuō)明此對(duì)象沒(méi)有被引用,也就是“死對(duì)象”,將會(huì)被垃圾回收.
引用計(jì)數(shù)法有一個(gè)缺陷就是無(wú)法解決循環(huán)引用問(wèn)題竟块,也就是說(shuō)當(dāng)對(duì)象A引用對(duì)象B壶运,對(duì)象B又引用者對(duì)象A,那么此時(shí)A,B對(duì)象的引用計(jì)數(shù)器都不為零浪秘,也就造成無(wú)法完成垃圾回收蒋情,所以主流的虛擬機(jī)都沒(méi)有采用這種算法。
可達(dá)性算法(引用鏈法)
該算法的思想是:從一個(gè)被稱為GC Roots的對(duì)象開(kāi)始向下搜索秫逝,如果一個(gè)對(duì)象到GC Roots沒(méi)有任何引用鏈相連時(shí)恕出,則說(shuō)明此對(duì)象不可用。
在java中可以作為GC Roots的對(duì)象有以下幾種:
- 虛擬機(jī)棧中引用的對(duì)象
- 方法區(qū)類靜態(tài)屬性引用的對(duì)象
- 方法區(qū)常量池引用的對(duì)象
- 本地方法棧JNI引用的對(duì)象
雖然這些算法可以判定一個(gè)對(duì)象是否能被回收违帆,但是當(dāng)滿足上述條件時(shí)浙巫,一個(gè)對(duì)象比不一定會(huì)被回收。當(dāng)一個(gè)對(duì)象不可達(dá)GC Root時(shí)刷后,這個(gè)對(duì)象并 不會(huì)立馬被回收的畴,而是出于一個(gè)死緩的階段,若要被真正的回收需要經(jīng)歷兩次標(biāo)記
如果對(duì)象在可達(dá)性分析中沒(méi)有與GC Root的引用鏈尝胆,那么此時(shí)就會(huì)被第一次標(biāo)記并且進(jìn)行一次篩選丧裁,篩選的條件是是否有必要執(zhí)行finalize()方法。當(dāng)對(duì)象沒(méi)有覆蓋finalize()方法或者已被虛擬機(jī)調(diào)用過(guò)含衔,那么就認(rèn)為是沒(méi)必要的煎娇。
如果該對(duì)象有必要執(zhí)行finalize()方法,那么這個(gè)對(duì)象將會(huì)放在一個(gè)稱為F-Queue的對(duì)隊(duì)列中贪染,虛擬機(jī)會(huì)觸發(fā)一個(gè)Finalize()線程去執(zhí)行缓呛,此線程是低優(yōu)先級(jí)的,并且虛擬機(jī)不會(huì)承諾一直等待它運(yùn)行完杭隙,這是因?yàn)槿绻鹒inalize()執(zhí)行緩慢或者發(fā)生了死鎖哟绊,那么就會(huì)造成F-Queue隊(duì)列一直等待,造成了內(nèi)存回收系統(tǒng)的崩潰痰憎。GC對(duì)處于F-Queue中的對(duì)象進(jìn)行第二次被標(biāo)記票髓,這時(shí),該對(duì)象將被移除”即將回收”集合铣耘,等待回收洽沟。
5、JVM中一次完整的GC是什么樣子的蜗细?對(duì)象如何晉升到老年代裆操?
- java堆 = 新生代+老年代;
- 新生代 = Eden + Suivivor(S0 + S1),默認(rèn)分配比例是8:1:1;
- 當(dāng)Eden區(qū)空間滿了的時(shí)候跷车,就會(huì)觸發(fā)一次Minor GC棘利,以收集新生代的垃圾,存活下來(lái)的對(duì)象會(huì)被分配到Survivor區(qū)
- 大對(duì)象(需要大量連續(xù)內(nèi)存空間的對(duì)象)會(huì)直接被分配到老年代
- 如果對(duì)象在Eden中出生朽缴,并且在經(jīng)歷過(guò)一次Minor GC之后仍然存活善玫,被分配到存活區(qū)的話,年齡+1密强,此后每經(jīng)歷過(guò)一次Minor GC并且存活下來(lái)茅郎,年齡就+1,當(dāng)年齡達(dá)到15的時(shí)候或渤,會(huì)被晉升到老年代系冗;
- 當(dāng)老年代滿了,而無(wú)法容納更多對(duì)象的話薪鹦,會(huì)觸發(fā)一次full gc掌敬;full gc存儲(chǔ)的是整個(gè)內(nèi)存堆(包括年輕代和老年代);池磁;
- Major GC是發(fā)生在老年代的GC奔害,清理老年區(qū),經(jīng)常會(huì)伴隨至少一次minor gc地熄;
6华临、運(yùn)行時(shí)數(shù)據(jù)區(qū)組成
- 程序計(jì)數(shù)器(Program Counter Register)
- Java虛擬機(jī)棧(Java Virtual Machine Stacks)
- 本地方法棧(Native Method Stack)
- Java堆(Java Heap)
- 方法區(qū)(Methed Area)
7、java中會(huì)存在內(nèi)存泄漏嗎端考?請(qǐng)簡(jiǎn)單描述
會(huì)雅潭。自己實(shí)現(xiàn)堆載的數(shù)據(jù)結(jié)構(gòu)時(shí)有可能會(huì)出現(xiàn)內(nèi)存泄露。
8却特、簡(jiǎn)述java垃圾回收機(jī)制?
在java中扶供,程序員是不需要顯示的去釋放一個(gè)對(duì)象的內(nèi)存的,而是由虛擬機(jī)自行執(zhí)行核偿。在JVM中诚欠,有一個(gè)垃圾回收線程顽染,它是低優(yōu)先級(jí)的漾岳,在正常情況下是不會(huì)執(zhí)行的,只有在虛擬機(jī)空閑或者當(dāng)前堆內(nèi)存不足時(shí)粉寞,才會(huì)觸發(fā)執(zhí)行尼荆,掃面那些沒(méi)有被任何引用的對(duì)象,并將它們添加到要回收的集合中唧垦,進(jìn)行回收捅儒。
9、Serial 與 Parallel GC 之間的不同之處?
Serial 與 Parallel 在 GC 執(zhí)行的時(shí)候都會(huì)引起 stop-the-world巧还。它們之間主要不同 serial 收集器是默認(rèn)的復(fù)制收集器鞭莽,執(zhí)行 GC 的時(shí)候只有一個(gè)線程,而parallel 收集器使用多個(gè) GC 線程來(lái)執(zhí)行麸祷。
10澎怒、Java中的垃圾回收算法?
java中有四種垃圾回收算法阶牍,分別是標(biāo)記清除法喷面、標(biāo)記整理法、復(fù)制算法走孽、分代收集算法惧辈;
標(biāo)記清除法:
第一步:利用可達(dá)性去遍歷內(nèi)存,把存活對(duì)象和垃圾對(duì)象進(jìn)行標(biāo)記磕瓷;
第二步:在遍歷一遍盒齿,將所有標(biāo)記的對(duì)象回收掉;
特點(diǎn):效率不行困食,標(biāo)記和清除的效率都不高县昂;標(biāo)記和清除后會(huì)產(chǎn)生大量的不連續(xù)的空間分片,可能會(huì)導(dǎo)致之后程序運(yùn)行的時(shí)候需分配大對(duì)象而找不到連續(xù)分片而不得不觸發(fā)一次GC陷舅;
標(biāo)記整理法:
第一步:利用可達(dá)性去遍歷內(nèi)存倒彰,把存活對(duì)象和垃圾對(duì)象進(jìn)行標(biāo)記;
第二步:將所有的存活的對(duì)象向一段移動(dòng)莱睁,將端邊界以外的對(duì)象都回收掉待讳;
特點(diǎn):適用于存活對(duì)象多,垃圾少的情況仰剿;需要整理的過(guò)程创淡,無(wú)空間碎片產(chǎn)生;
復(fù)制算法:
將內(nèi)存按照容量大小分為大小相等的兩塊南吮,每次只使用一塊琳彩,當(dāng)一塊使用完了,就將還存活的對(duì)象移到另一塊上部凑,然后在把使用過(guò)的內(nèi)存空間移除露乏;
特點(diǎn):不會(huì)產(chǎn)生空間碎片;內(nèi)存使用率極低涂邀;
分代收集算法:
根據(jù)內(nèi)存對(duì)象的存活周期不同瘟仿,將內(nèi)存劃分成幾塊,java虛擬機(jī)一般將內(nèi)存分成新生代和老生代比勉,在新生代中劳较,有大量對(duì)象死去和少量對(duì)象存活驹止,所以采用復(fù)制算法,只需要付出少量存活對(duì)象的復(fù)制成本就可以完成收集观蜗;老年代中因?yàn)閷?duì)象的存活率極高臊恋,沒(méi)有額外的空間對(duì)他進(jìn)行分配擔(dān)保,所以采用標(biāo)記清理或者標(biāo)記整理算法進(jìn)行回收墓捻;
11捞镰、怎樣通過(guò) Java 程序來(lái)判斷 JVM 是 32 位 還是 64位?
你可以檢查某些系統(tǒng)屬性如 sun.arch.data.model 或 os.arch 來(lái)獲取該信息毙替。
12岸售、java中垃圾收集的方法有哪些?
- 標(biāo)記-清除:
這是垃圾收集算法中最基礎(chǔ)的,根據(jù)名字就可以知道厂画,它的思想就是標(biāo)記哪些要被回收的對(duì)象凸丸,然后統(tǒng)一回收。這種方法很簡(jiǎn)單袱院,但是會(huì)有兩個(gè)主要問(wèn)題:1.效率不高屎慢,標(biāo)記和清除的效率都很低;2.會(huì)產(chǎn)生大量不連續(xù)的內(nèi)存碎片忽洛,導(dǎo)致以后程序在分配較大的對(duì)象時(shí)腻惠,由于沒(méi)有充足的連續(xù)內(nèi)存而提前觸發(fā)一次GC動(dòng)作。
- 復(fù)制算法:
為了解決效率問(wèn)題欲虚,復(fù)制算法將可用內(nèi)存按容量劃分為相等的兩部分集灌,然后每次只使用其中的一塊,當(dāng)一塊內(nèi)存用完時(shí)复哆,就將還存活的對(duì)象復(fù)制到第二塊內(nèi)存上欣喧,然后一次性清楚完第一塊內(nèi)存,再將第二塊上的對(duì)象復(fù)制到第一塊梯找。但是這種方式唆阿,內(nèi)存的代價(jià)太高,每次基本上都要浪費(fèi)一般的內(nèi)存锈锤。
于是將該算法進(jìn)行了改進(jìn)驯鳖,內(nèi)存區(qū)域不再是按照1:1去劃分,而是將內(nèi)存劃分為8:1:1三部分久免,較大那份內(nèi)存交Eden區(qū)浅辙,其余是兩塊較小的內(nèi)存區(qū)叫Survior區(qū)。每次都會(huì)優(yōu)先使用Eden區(qū)妄壶,若Eden區(qū)滿摔握,就將對(duì)象復(fù)制到第二塊內(nèi)存區(qū)上寄狼,然后清除Eden區(qū)丁寄,如果此時(shí)存活的對(duì)象太多氨淌,以至于Survivor不夠時(shí),會(huì)將這些對(duì)象通過(guò)分配擔(dān)保機(jī)制復(fù)制到老年代中伊磺。(java堆又分為新生代和老年代)
- 標(biāo)記-整理
該算法主要是為了解決標(biāo)記-清除盛正,產(chǎn)生大量?jī)?nèi)存碎片的問(wèn)題;當(dāng)對(duì)象存活率較高時(shí)屑埋,也解決了復(fù)制算法的效率問(wèn)題豪筝。它的不同之處就是在清除對(duì)象的時(shí)候現(xiàn)將可回收對(duì)象移動(dòng)到一端,然后清除掉端邊界以外的對(duì)象摘能,這樣就不會(huì)產(chǎn)生內(nèi)存碎片了续崖。
- 分代收集:
現(xiàn)在的虛擬機(jī)垃圾收集大多采用這種方式,它根據(jù)對(duì)象的生存周期团搞,將堆分為新生代和老年代严望。在新生代中,由于對(duì)象生存期短逻恐,每次回收都會(huì)有大量對(duì)象死去像吻,那么這時(shí)就采用復(fù)制算法。老年代里的對(duì)象存活率較高复隆,沒(méi)有額外的空間進(jìn)行分配擔(dān)保拨匆,所以可以使用標(biāo)記-整理 或者 標(biāo)記-清除。
13挽拂、如何判斷一個(gè)對(duì)象是否應(yīng)該被回收惭每?
判斷對(duì)象是否存活一般有兩種方式:
- 引用計(jì)數(shù):每個(gè)對(duì)象有一個(gè)引用計(jì)數(shù)屬性,新增一個(gè)引用時(shí)計(jì)數(shù)加1亏栈,引用釋放時(shí)計(jì)數(shù)減1洪鸭,計(jì)數(shù)為0時(shí)可以回收。此方法簡(jiǎn)單仑扑,無(wú)法解決對(duì)象相互循環(huán)引用的問(wèn)題览爵。
- 可達(dá)性分析(Reachability Analysis):從GC Roots開(kāi)始向下搜索,搜索所走過(guò)的路徑稱為引用鏈镇饮。當(dāng)一個(gè)對(duì)象到GC Roots沒(méi)有任何引用鏈相連時(shí)蜓竹,則證明此對(duì)象是不可用的,不可達(dá)對(duì)象储藐。
14俱济、調(diào)優(yōu)命令
Sun JDK監(jiān)控和故障處理命令有jps jstat jmap jhat jstack jinfo
- jps,JVM Process Status Tool,顯示指定系統(tǒng)內(nèi)所有的HotSpot虛擬機(jī)進(jìn)程钙勃。
- jstat蛛碌,JVM statistics Monitoring是用于監(jiān)視虛擬機(jī)運(yùn)行時(shí)狀態(tài)信息的命令,它可以顯示出虛擬機(jī)進(jìn)程中的類裝載辖源、內(nèi)存蔚携、垃圾收集希太、JIT編譯等運(yùn)行數(shù)據(jù)。
- jmap酝蜒,JVM Memory Map命令用于生成heap dump文件
- jhat誊辉,JVM Heap Analysis Tool命令是與jmap搭配使用,用來(lái)分析jmap生成的dump亡脑,jhat內(nèi)置了一個(gè)微型的HTTP/HTML服務(wù)器堕澄,生成dump的分析結(jié)果后,可以在瀏覽器中查看
- jstack霉咨,用于生成java虛擬機(jī)當(dāng)前時(shí)刻的線程快照蛙紫。
- jinfo,JVM Configuration info 這個(gè)命令作用是實(shí)時(shí)查看和調(diào)整虛擬機(jī)運(yùn)行參數(shù)途戒。
15惊来、JRE、JDK棺滞、JVM 及 JIT 之間有什么不同裁蚁?
- JRE 代表 Java 運(yùn)行時(shí)(Java run-time),是運(yùn)行 Java 引用所必須的继准。
- JDK 代表 Java 開(kāi)發(fā)工具(Java development kit)枉证,是 Java 程序打開(kāi)發(fā)工具,如 Java編譯器移必,它也包含 JRE室谚。
- JVM 代表 Java 虛擬機(jī)(Java virtual machine),它的責(zé)任是運(yùn)行 Java 應(yīng)用崔泵。JIT 代表即時(shí)編譯(Just In Time compilation)秒赤,當(dāng)代碼執(zhí)行的次數(shù)超過(guò)一定的閾值時(shí),會(huì)將 Java 字節(jié)碼轉(zhuǎn)換為本地代碼憎瘸,如入篮,主要的熱點(diǎn)代碼會(huì)被準(zhǔn)換為本地代碼,這樣有利大幅度提高 Java 應(yīng)用的性能幌甘。
16潮售、如何判斷一個(gè)對(duì)象是否存活?
判斷一個(gè)對(duì)象是否存活锅风,分為兩種算法1:引用計(jì)數(shù)法酥诽;2:可達(dá)性分析算法;
- 引用計(jì)數(shù)法:
給每一個(gè)對(duì)象設(shè)置一個(gè)引用計(jì)數(shù)器皱埠,當(dāng)有一個(gè)地方引用該對(duì)象的時(shí)候肮帐,引用計(jì)數(shù)器就+1,引用失效時(shí)边器,引用計(jì)數(shù)器就-1训枢;當(dāng)引用計(jì)數(shù)器為0的時(shí)候托修,就說(shuō)明這個(gè)對(duì)象沒(méi)有被引用,也就是垃圾對(duì)象肮砾,等待回收诀黍;
缺點(diǎn):無(wú)法解決循環(huán)引用的問(wèn)題袋坑,當(dāng)A引用B仗处,B也引用A的時(shí)候,此時(shí)AB對(duì)象的引用都不為0枣宫,此時(shí)也就無(wú)法垃圾回收婆誓,所以一般主流虛擬機(jī)都不采用這個(gè)方法;
- 可達(dá)性分析法
從一個(gè)被稱為GC Roots的對(duì)象向下搜索也颤,如果一個(gè)對(duì)象到GC Roots沒(méi)有任何引用鏈相連接時(shí)洋幻,說(shuō)明此對(duì)象不可用,在java中可以作為GC Roots的對(duì)象有以下幾種:
- 虛擬機(jī)棧中引用的對(duì)象
- 方法區(qū)類靜態(tài)屬性引用的變量
- 方法區(qū)常量池引用的對(duì)象
- 本地方法棧JNI引用的對(duì)象
但一個(gè)對(duì)象滿足上述條件的時(shí)候翅娶,不會(huì)馬上被回收文留,還需要進(jìn)行兩次標(biāo)記;第一次標(biāo)記:判斷當(dāng)前對(duì)象是否有finalize()方法并且該方法沒(méi)有被執(zhí)行過(guò)竭沫,若不存在則標(biāo)記為垃圾對(duì)象燥翅,等待回收;若有的話蜕提,則進(jìn)行第二次標(biāo)記森书;第二次標(biāo)記將當(dāng)前對(duì)象放入F-Queue隊(duì)列,并生成一個(gè)finalize線程去執(zhí)行該方法谎势,虛擬機(jī)不保證該方法一定會(huì)被執(zhí)行凛膏,這是因?yàn)槿绻€程執(zhí)行緩慢或進(jìn)入了死鎖,會(huì)導(dǎo)致回收系統(tǒng)的崩潰脏榆;如果執(zhí)行了finalize方法之后仍然沒(méi)有與GC Roots有直接或者間接的引用猖毫,則該對(duì)象會(huì)被回收;
17须喂、有哪幾種垃圾回收器鄙麦,有哪些優(yōu)缺點(diǎn)?cms和g1的區(qū)別镊折?
垃圾回收器主要分為以下幾種:Serial胯府、ParNew、Parallel Scavenge恨胚、Serial Old骂因、Parallel Old、CMS赃泡、G1寒波;
- Serial:
單線程的收集器乘盼,收集垃圾時(shí),必須stop the world俄烁,使用復(fù)制算法绸栅。
- ParNew:
Serial收集器的多線程版本,也需要stop the world页屠,復(fù)制算法.
- Parallel Scavenge:
新生代收集器粹胯,復(fù)制算法的收集器,并發(fā)的多線程收集器辰企,目標(biāo)是達(dá)到一個(gè)可控的吞吐量风纠,和ParNew的最大區(qū)別是GC自動(dòng)調(diào)節(jié)策略;虛擬機(jī)會(huì)根據(jù)系統(tǒng)的運(yùn)行狀態(tài)收集性能監(jiān)控信息牢贸,動(dòng)態(tài)設(shè)置這些參數(shù)竹观,以提供最優(yōu)停頓時(shí)間和最高的吞吐量;
- Serial Old:
Serial收集器的老年代版本潜索,單線程收集器臭增,使用標(biāo)記整理算法。
- Parallel Old:
是Parallel Scavenge收集器的老年代版本竹习,使用多線程誊抛,標(biāo)記-整理算法。
- CMS:
是一種以獲得最短回收停頓時(shí)間為目標(biāo)的收集器由驹,標(biāo)記清除算法芍锚,運(yùn)作過(guò)程:初始標(biāo)記,并發(fā)標(biāo)記蔓榄,重新標(biāo)記并炮,并發(fā)清除,收集結(jié)束會(huì)產(chǎn)生大量空間碎片甥郑;
- G1:
標(biāo)記整理算法實(shí)現(xiàn)逃魄,運(yùn)作流程主要包括以下:初始標(biāo)記,并發(fā)標(biāo)記澜搅,最終標(biāo)記伍俘,篩選回收。不會(huì)產(chǎn)生空間碎片勉躺,可以精確地控制停頓癌瘾;
G1將整個(gè)堆分為大小相等的多個(gè)Region(區(qū)域),G1跟蹤每個(gè)區(qū)域的垃圾大小饵溅,在后臺(tái)維護(hù)一個(gè)優(yōu)先級(jí)列表妨退,每次根據(jù)允許的收集時(shí)間,優(yōu)先回收價(jià)值最大的區(qū)域,已達(dá)到在有限時(shí)間內(nèi)獲取盡可能高的回收效率咬荷;
18冠句、類加載器雙親委派模型機(jī)制?
當(dāng)一個(gè)類收到了類加載請(qǐng)求時(shí)幸乒,不會(huì)自己先去加載這個(gè)類懦底,而是將其委派給父類,由父類去加載罕扎,如果此時(shí)父類不能加載聚唐,反饋給子類,由子類去完成類的加載壳影。
19拱层、什么是類加載器弥臼,類加載器有哪些?
實(shí)現(xiàn)通過(guò)類的權(quán)限定名獲取該類的二進(jìn)制字節(jié)流的代碼塊叫做類加載器宴咧。
主要有一下四種類加載器:
- 啟動(dòng)類加載器(Bootstrap ClassLoader)用來(lái)加載java核心類庫(kù),無(wú)法被java程序直接引用径缅。
- 擴(kuò)展類加載器(extensions class loader):它用來(lái)加載 Java 的擴(kuò)展庫(kù)掺栅。Java 虛擬機(jī)的實(shí)現(xiàn)會(huì)提供一個(gè)擴(kuò)展庫(kù)目錄。該類加載器在此目錄里面查找并加載 Java 類纳猪。
- 系統(tǒng)類加載器(system class loader):它根據(jù) Java 應(yīng)用的類路徑(CLASSPATH)來(lái)加載 Java 類氧卧。一般來(lái)說(shuō),Java 應(yīng)用的類都是由它來(lái)完成加載的氏堤∩尘可以通過(guò) ClassLoader.getSystemClassLoader()來(lái)獲取它。
- 用戶自定義類加載器鼠锈,通過(guò)繼承 java.lang.ClassLoader類的方式實(shí)現(xiàn)闪檬。
20、調(diào)優(yōu)工具
常用調(diào)優(yōu)工具分為兩類,jdk自帶監(jiān)控工具:jconsole和jvisualvm购笆,第三方有:MAT(Memory Analyzer Tool)粗悯、GChisto。
- jconsole同欠,Java Monitoring and Management Console是從java5開(kāi)始样傍,在JDK中自帶的java監(jiān)控和管理控制臺(tái),用于對(duì)JVM中內(nèi)存铺遂,線程和類等的監(jiān)控
- jvisualvm衫哥,jdk自帶全能工具,可以分析內(nèi)存快照襟锐、線程快照撤逢;監(jiān)控內(nèi)存變化、GC變化等。
- MAT笛质,Memory Analyzer Tool泉沾,一個(gè)基于Eclipse的內(nèi)存分析工具,是一個(gè)快速妇押、功能豐富的Java heap分析工具跷究,它可以幫助我們查找內(nèi)存泄漏和減少內(nèi)存消耗
- GChisto,一款專業(yè)分析gc日志的工具
21敲霍、JVM永久代中會(huì)發(fā)生垃圾回收么
垃圾回收不會(huì)發(fā)生在永久代俊马,如果永久代滿了或者是超過(guò)了臨界值,會(huì)觸發(fā)完全垃圾回收(Full GC)肩杈。如果你仔細(xì)查看垃圾收集器的輸出信息柴我,就會(huì)發(fā)現(xiàn)永久代也是被回收的。這就是為什么正確的永久代大小對(duì)避免Full GC是非常重要的原因扩然。請(qǐng)參考下Java8:從永久代到元數(shù)據(jù)區(qū) (注:Java8中已經(jīng)移除了永久代艘儒,新加了一個(gè)叫做元數(shù)據(jù)區(qū)的native內(nèi)存區(qū))
22、JVM 內(nèi)存區(qū)域
VM 內(nèi)存區(qū)域主要分為線程私有區(qū)域【程序計(jì)數(shù)器夫偶、虛擬機(jī)棧界睁、本地方法區(qū)】、線程共享區(qū)域【JAVA 堆兵拢、方法區(qū)】翻斟、直接內(nèi)存。
線程私有數(shù)據(jù)區(qū)域生命周期與線程相同, 依賴用戶線程的啟動(dòng)/結(jié)束 而 創(chuàng)建/銷毀(在 Hotspot VM 內(nèi), 每個(gè)線程都與操作系統(tǒng)的本地線程直接映射, 因此這部分內(nèi)存區(qū)域的存/否跟隨本地線程的生/死對(duì)應(yīng))说铃。
線程共享區(qū)域隨虛擬機(jī)的啟動(dòng)/關(guān)閉而創(chuàng)建/銷毀访惜。
直接內(nèi)存并不是 JVM 運(yùn)行時(shí)數(shù)據(jù)區(qū)的一部分, 但也會(huì)被頻繁的使用: 在 JDK 1.4 引入的 NIO 提供了基于Channel與 Buffer的IO方式, 它可以使用Native函數(shù)庫(kù)直接分配堆外內(nèi)存, 然后使用DirectByteBuffer 對(duì)象作為這塊內(nèi)存的引用進(jìn)行操作(詳見(jiàn): Java I/O 擴(kuò)展), 這樣就避免了在 Java堆和 Native 堆中來(lái)回復(fù)制數(shù)據(jù), 因此在一些場(chǎng)景中可以顯著提高性能。
23腻扇、虛擬機(jī)棧(線程私有)
是描述java方法執(zhí)行的內(nèi)存模型债热,每個(gè)方法在執(zhí)行的同時(shí)都會(huì)創(chuàng)建一個(gè)棧幀(Stack Frame)用于存儲(chǔ)局部變量表、操作數(shù)棧衙解、動(dòng)態(tài)鏈接阳柔、方法出口等信息。 每一個(gè)方法從調(diào)用直至執(zhí)行完成的過(guò)程蚓峦,就對(duì)應(yīng)著一個(gè)棧幀在虛擬機(jī)棧中入棧到出棧的過(guò)程舌剂。
棧幀( Frame)是用來(lái)存儲(chǔ)數(shù)據(jù)和部分過(guò)程結(jié)果的數(shù)據(jù)結(jié)構(gòu),同時(shí)也被用來(lái)處理動(dòng)態(tài)鏈接(Dynamic Linking)暑椰、 方法返回值和異常分派(Dispatch Exception)霍转。 棧幀隨著方法調(diào)用而創(chuàng)建,隨著方法結(jié)束而銷毀——無(wú)論方法是正常完成還是異常完成(拋出了在方法內(nèi)未被捕獲的異常)都算作方法結(jié)束一汽。
24避消、引用的分類
- 強(qiáng)引用:GC時(shí)不會(huì)被回收
- 軟引用:描述有用但不是必須的對(duì)象低滩,在發(fā)生內(nèi)存溢出異常之前被回收
- 弱引用:描述有用但不是必須的對(duì)象,在下一次GC時(shí)被回收
- 虛引用(幽靈引用/幻影引用):無(wú)法通過(guò)虛引用獲得對(duì)象岩喷,用PhantomReference實(shí)現(xiàn)虛引用恕沫,虛引用用來(lái)在GC時(shí)返回一個(gè)通知。
25纱意、方法區(qū)/永久代(線程共享)
即我們常說(shuō)的永久代(Permanent Generation), 用于存儲(chǔ)被 JVM 加載的類信息婶溯、常量、靜態(tài)變量即偷霉、時(shí)編譯器編譯后的代碼等數(shù)據(jù).HotSpot VM把GC分代收集擴(kuò)展至方法區(qū), 即使用Java堆的永久代來(lái)實(shí)現(xiàn)方法區(qū), 這樣 HotSpot 的垃圾收集器就可以像管理 Java 堆一樣管理這部分內(nèi)存,而不必為方法區(qū)開(kāi)發(fā)專門(mén)的內(nèi)存管理器(永久帶的內(nèi)存回收的主要目標(biāo)是針對(duì)常量池的回收和類型的卸載, 因此收益一般很小) 迄委。
運(yùn)行時(shí)常量池(Runtime Constant Pool)是方法區(qū)的一部分。 Class 文件中除了有類的版本类少、字段叙身、方法、接口等描述等信息外硫狞,還有一項(xiàng)信息是常量池 (Constant Pool Table)信轿,用于存放編譯期生成的各種字面量和符號(hào)引用,這部分內(nèi)容將在類加載后存放到方法區(qū)的運(yùn)行時(shí)常量池中妓忍。 Java 虛擬機(jī)對(duì) Class 文件的每一部分(自然也包括常量池)的格式都有嚴(yán)格的規(guī)定虏两,每一個(gè)字節(jié)用于存儲(chǔ)哪種數(shù)據(jù)都必須符合規(guī)范上的要求愧旦,這樣才會(huì)被虛擬機(jī)認(rèn)可世剖、裝載和執(zhí)行吩跋。