您好,登錄后才能下訂單哦!
很多人說(shuō)JVM是不是真的要學(xué)?面試官都會(huì)問(wèn)JVM的問(wèn)題嗎?很重要嗎?
的確很重要。
隨著互聯(lián)網(wǎng)的發(fā)展,高并發(fā)高可用、快速響應(yīng)成為軟件的必須,而JVM與這些有著密切關(guān)聯(lián)。
我們?cè)诒M情享受Java虛擬機(jī)帶來(lái)好處的同時(shí),還應(yīng)該去了解和思考“這些技術(shù)特性是如何實(shí)現(xiàn)的”,去了解最底層的原理。只有熟悉JVM,你才能在遇到OutOfMemory等異常時(shí),不會(huì)束手無(wú)策,不會(huì)一臉懵逼的上網(wǎng)找解決辦法,最后就算改了幾個(gè)啟動(dòng)參數(shù)解決了問(wèn)題,也還是云里霧里。
其實(shí),“為什么學(xué)Java虛擬機(jī)”這個(gè)問(wèn)題,就和“為什么要學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)和算法”是一個(gè)道理:工欲善其事,必先利其器??梢哉f(shuō),Java虛擬機(jī)就是每一位Java工程師進(jìn)階加薪的利器,你想往上升,你想深入技術(shù),不想一直停留在簡(jiǎn)單開(kāi)發(fā),或者你在做Java性能分析、調(diào)優(yōu)工作時(shí),那么,Java虛擬機(jī)絕對(duì)是一把助力的利劍。
1.內(nèi)存模型以及分區(qū),需要詳細(xì)到每個(gè)區(qū)放什么。
JVM 分為堆區(qū)和棧區(qū),還有方法區(qū),初始化的對(duì)象放在堆里面,引用放在棧里面,class類信息常量池(static常量和static變量)等放在方法區(qū)
new:
方法區(qū):主要是存儲(chǔ)類信息,常量池(static常量和static變量),編譯后的代碼(字節(jié)碼)等數(shù)據(jù)
堆:初始化的對(duì)象,成員變量 (那種非static的變量),所有的對(duì)象實(shí)例和數(shù)組都要在堆上分配
棧:棧的結(jié)構(gòu)是棧幀組成的,調(diào)用一個(gè)方法就壓入一幀,幀上面存儲(chǔ)局部變量表,操作數(shù)棧,方法出口等信息,局部變量表存放的是8大基礎(chǔ)類型加上一個(gè)應(yīng)用類型,所以還是一個(gè)指向地址的指針
本地方法棧:主要為Native方法服務(wù)
程序計(jì)數(shù)器:記錄當(dāng)前線程執(zhí)行的行號(hào)
2.堆里面的分區(qū):Eden,survival (from+ to),老年代,各自的特點(diǎn)。
堆里面分為新生代和老生代(java8取消了永久代,采用了Metaspace),新生代包含Eden+Survivor區(qū),survivor區(qū)里面分為from和to區(qū),內(nèi)存回收時(shí),如果用的是復(fù)制算法,從from復(fù)制到to,當(dāng)經(jīng)過(guò)一次或者多次GC之后,存活下來(lái)的對(duì)象會(huì)被移動(dòng)到老年區(qū),當(dāng)JVM內(nèi)存不夠用的時(shí)候,會(huì)觸發(fā)Full GC,清理JVM老年區(qū)
當(dāng)新生區(qū)滿了之后會(huì)觸發(fā)YGC,先把存活的對(duì)象放到其中一個(gè)Survice 區(qū),然后進(jìn)行垃圾清理。因?yàn)槿绻麅H僅清理需要?jiǎng)h除的對(duì)象,這樣會(huì)導(dǎo)致內(nèi)存碎 片,因此一般會(huì)把Eden 進(jìn)行完全的清理,然后整理內(nèi)存。那么下次GC 的時(shí)候, 就會(huì)使用下一個(gè)Survive,這樣循環(huán)使用。如果有特別大的對(duì)象,新生代放不下, 就會(huì)使用老年代的擔(dān)保,直接放到老年代里面。因?yàn)镴VM 認(rèn)為,一般大對(duì)象的存 活時(shí)間一般比較久遠(yuǎn)。
3.對(duì)象創(chuàng)建方法,對(duì)象的內(nèi)存分配,對(duì)象的訪問(wèn)定位。
new 一個(gè)對(duì)象
4.GC的兩種判定方法:
引用計(jì)數(shù)法:指的是如果某個(gè)地方引用了這個(gè)對(duì)象就+1,如果失效了就-1,當(dāng)為0就會(huì)回收但是JVM沒(méi)有用這種方式,因?yàn)闊o(wú)法判定相互循環(huán)引用(A引用B,B引用A)的情況
引用鏈法: 通過(guò)一種GC ROOT的對(duì)象(方法區(qū)中靜態(tài)變量引用的對(duì)象等-static變量)來(lái)判斷,如果有一條鏈能夠到達(dá)GC ROOT就說(shuō)明,不能到達(dá)GC ROOT就說(shuō)明可以回收
5.SafePoint是什么
比如GC的時(shí)候必須要等到Java線程都進(jìn)入到safepoint的時(shí)候VMThread才能開(kāi)始執(zhí)行GC,
循環(huán)的末尾 (防止大循環(huán)的時(shí)候一直不進(jìn)入safepoint,而其他線程在等待它進(jìn)入safepoint)
方法返回前
調(diào)用方法的call之后
拋出異常的位置
6.GC的三種收集方法:標(biāo)記清除、標(biāo)記整理、復(fù)制算法的原理與特點(diǎn),分別用在什么地方,如果讓你優(yōu)化收集方法,有什么思路?
先標(biāo)記,標(biāo)記完畢之后再清除,效率不高,會(huì)產(chǎn)生碎片
復(fù)制算法:分為8:1的Eden區(qū)和survivor區(qū),就是上面談到的YGC
標(biāo)記整理:標(biāo)記完畢之后,讓所有存活的對(duì)象向一端移動(dòng)
7.GC收集器有哪些?CMS收集器與G1收集器的特點(diǎn)。
并行收集器:串行收集器使用一個(gè)單獨(dú)的線程進(jìn)行收集,GC時(shí)服務(wù)有停頓時(shí)間
串行收集器:次要回收中使用多線程來(lái)執(zhí)行
CMS收集器是基于“標(biāo)記—清除”算法實(shí)現(xiàn)的,經(jīng)過(guò)多次標(biāo)記才會(huì)被清除
G1從整體來(lái)看是基于“標(biāo)記—整理”算法實(shí)現(xiàn)的收集器,從局部(兩個(gè)Region之間)上來(lái)看是基于“復(fù)制”算法實(shí)現(xiàn)的
8.Minor GC與Full GC分別在什么時(shí)候發(fā)生?
新生代內(nèi)存不夠用時(shí)候發(fā)生MGC也叫YGC,JVM內(nèi)存不夠的時(shí)候發(fā)生FGC
9.幾種常用的內(nèi)存調(diào)試工具:jmap、jstack、jconsole、jhat
jstack 可以看當(dāng)前棧的情況,jmap 查看內(nèi)存,jhat 進(jìn)行 dump 堆的信息
mat(eclipse 的也要了解一下)
10.類加載的幾個(gè)過(guò)程
加載、驗(yàn)證、準(zhǔn)備、解析、初始化。然后是使用和卸載了
通過(guò)全限定名來(lái)加載生成 class 對(duì)象到內(nèi)存中,然后進(jìn)行驗(yàn)證這個(gè) class 文件,包括文
件格式校驗(yàn)、元數(shù)據(jù)驗(yàn)證,字節(jié)碼校驗(yàn)等。準(zhǔn)備是對(duì)這個(gè)對(duì)象分配內(nèi)存。解析是將符
號(hào)引用轉(zhuǎn)化為直接引用(指針引用),初始化就是開(kāi)始執(zhí)行構(gòu)造器的代碼
11.JVM內(nèi)存分哪幾個(gè)區(qū),每個(gè)區(qū)的作用是什么?
java 虛擬機(jī)主要分為以下一個(gè)區(qū):
方法區(qū):
12.如和判斷一個(gè)對(duì)象是否存活?(或者GC對(duì)象的判定方法)
判斷一個(gè)對(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)槿绻?finalize()執(zhí)行緩慢或者發(fā)生了死鎖,那么就會(huì)造成 F-
Queue 隊(duì)列一直等待,造成了內(nèi)存回收系統(tǒng)的崩潰。GC 對(duì)處于 F-Queue 中的對(duì)象進(jìn)行
第二次被標(biāo)記,這時(shí),該對(duì)象將被移除”即將回收”集合,等待回收。
13.簡(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)行回收。
14.java中垃圾收集的方法有哪些?
15.java內(nèi)存模型
java 內(nèi)存模型(JMM)是線程間通信的控制機(jī)制.JMM 定義了主內(nèi)存和線程之間抽象關(guān)系。
線程之間的共享變量存儲(chǔ)在主內(nèi)存(main memory)中,每個(gè)線程都有一個(gè)私有的本地
內(nèi)存(local memory),本地內(nèi)存中存儲(chǔ)了該線程以讀/寫共享變量的副本。本地內(nèi)存是
JMM 的一個(gè)抽象概念,并不真實(shí)存在。它涵蓋了緩存,寫緩沖區(qū),寄存器以及其他的硬
件和編譯器優(yōu)化。Java 內(nèi)存模型的抽象示意圖如下:
從上圖來(lái)看,線程 A 與線程 B 之間如要通信的話,必須要經(jīng)歷下面 2 個(gè)步驟:
16.java類加載過(guò)程?
java 類加載需要經(jīng)歷一下 7 個(gè)過(guò)程:
加載
加載時(shí)類加載的第一個(gè)過(guò)程,在這個(gè)階段,將完成一下三件事情:
解析
該階段主要完成符號(hào)引用到直接引用的轉(zhuǎn)換動(dòng)作。解析動(dòng)作并不一定在初始化動(dòng)作完成之
前,也有可能在初始化之后。
初始化
初始化時(shí)類加載的最后一步,前面的類加載過(guò)程,除了在加載階段用戶應(yīng)用程序可以通過(guò)
自定義類加載器參與之外,其余動(dòng)作完全由虛擬機(jī)主導(dǎo)和控制。到了初始化階段,才真正
開(kāi)始執(zhí)行類中定義的 Java 程序代碼。
17. 簡(jiǎn)述java類加載機(jī)制?
虛擬機(jī)把描述類的數(shù)據(jù)從 Class 文件加載到內(nèi)存,并對(duì)數(shù)據(jù)進(jìn)行校驗(yàn),解析和初始化,最
終形成可以被虛擬機(jī)直接使用的 java 類型。
18. 類加載器雙親委派模型機(jī)制?
當(dāng)一個(gè)類收到了類加載請(qǐng)求時(shí),不會(huì)自己先去加載這個(gè)類,而是將其委派給父類,由父類
去加載,如果此時(shí)父類不能加載,反饋給子類,由子類去完成類的加載。
19.什么是類加載器,類加載器有哪些?
實(shí)現(xiàn)通過(guò)類的權(quán)限定名獲取該類的二進(jìn)制字節(jié)流的代碼塊叫做類加載器。
主要有一下四種類加載器:
20.簡(jiǎn)述java內(nèi)存分配與回收策率以及Minor GC和Major GC
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。