分享一套之前整理的JVM入門試題(含答案)

簡書 慢黑八
轉(zhuǎn)載請注明原創(chuàng)出處纱昧,謝謝刨啸!
如果讀完覺得有收獲的話,歡迎點贊加關(guān)注

1识脆、(5分)下題方法localVar1()中變量b所占槽位index為( )设联,localVar2()中變量b所占槽位index為 ( )

private void localVar1() {
        int a=0;
        System.out.println(a);
        int b=0;
    }
    private void localVar2() {
        {
            int a = 0;
            System.out.println(a);
        }
        int b = 0;
    }

答:使用jclasslib查看class信息 加匈,此題考的是棧上數(shù)據(jù)局部變量表的槽位復(fù)用仑荐,如下圖localVar1()方法中this占0位雕拼,a的index是1,b的index是2粘招,localVar2()方法中啥寇,當a處于代碼塊中的時候,代碼塊結(jié)束a的槽位釋放洒扎,b的槽位將會使用index=1的槽位辑甜,這樣做的好處是節(jié)省了空間,localVar2方法塊執(zhí)行后袍冷,a的槽位釋放可以提供給b使用磷醋,a引用的對象也可以在滿足垃圾回收的條件。


image.png

image.png

2胡诗、(20分)在java7中邓线,畫圖描述一下程序,在類加載器煌恢、方法區(qū)骇陈、堆、解釋執(zhí)行器瑰抵、pc寄存器你雌、java棧、本地方法棧二汛、CodeCache婿崭、垃圾回收器中是如何關(guān)聯(lián)執(zhí)行

public class A {
    public static void main(String[] args) {
        A a = new A();
        a.fn();
    }
    public void fn() {
        System.out.println("Hello World");
    }
}

答:如下圖所示


image.png
  1. A.java編譯后生成A.class字節(jié)碼文件
  2. 類加載子系統(tǒng)負責從文件系統(tǒng)或網(wǎng)絡(luò)中加載Class信息,加載的類信息存放于一塊稱為方法區(qū)(JDK1.7叫永久代肴颊,JDK1.8中叫做元空間)的內(nèi)存空間氓栈。除了類的信息外,方法區(qū)中還會存放運行時的常量池信息苫昌,包括字符串常量和數(shù)字常量等颤绕。
  3. Java字節(jié)碼對于JVM就相當于匯編語言對于計算機幸海。JVM啟動后會查找?guī)в衜ain方法開始執(zhí)行祟身,字節(jié)碼會被JVM最后翻譯為計算機可以看懂的機器碼在CUP中運行,這個過程由“解釋執(zhí)行器”進行解釋執(zhí)行物独。還有一部分熱點方法字節(jié)碼由JIT“即時編譯器”(即時編譯器的解釋參見第7題)進行了編譯優(yōu)化袜硫,編譯優(yōu)化后的機器碼可以更加高效的執(zhí)行。
  4. PC寄存器(也叫程序計數(shù)器)也是每個線程的私有空間挡篓,Java虛擬機會為每一個Java線程創(chuàng)建PC寄存器婉陷。在任意時刻帚称,每一個線程總是在執(zhí)行一個方法,這個被執(zhí)行的方法叫當前方法秽澳,如果當前方法不是本地方法闯睹,PC寄存器就會指向當前正在被執(zhí)行的指令。它可以看作是當前線程所執(zhí)行的字節(jié)碼的行號指示器担神。
  5. Java棧是一塊私有的空間楼吃,先進后出的數(shù)據(jù)結(jié)構(gòu),只支持出棧和入棧兩種操縱妄讯。主要保存的內(nèi)容為棧幀孩锡,每一次函數(shù)調(diào)用(例如:調(diào)用main方法,fn方法)都會有一個對應(yīng)的棧幀被壓入Java棧亥贸。當前正在執(zhí)行的函數(shù)所對應(yīng)的幀就是當前的幀(棧頂)躬窜,它保存著當前函數(shù)的局部變量、棧幀數(shù)據(jù)(例如炕置,對象A()的引用)和中間運算結(jié)果數(shù)據(jù)荣挨。在方法執(zhí)行結(jié)束、異常朴摊、return之后Java棧會把方法從棧上彈出垦沉。
  6. Java堆在虛擬機啟動的時候建立,它是Java程序最主要的內(nèi)存工作區(qū)域仍劈。在字節(jié)碼執(zhí)行到new A()的時候厕倍,對象在堆空間被創(chuàng)建,嚴格意義上來說對象創(chuàng)建的過程要更復(fù)雜一些贩疙。簡單來說讹弯,虛擬機會先把對象嘗試在棧上分配(棧上分配的解釋參見第4題),當不滿足棧上分配的條件后这溅,對象會在在堆中分配组民。
    分配的優(yōu)先級是:棧上分配 > TLAB分配 > 大對象直接老年代分配 > 新生代分配
  7. 垃圾回收系統(tǒng)是Java虛擬機的重要組成部分,垃圾回收器可以對方法區(qū)悲靴、Java堆和直接內(nèi)存進行回收臭胜。其中,Java堆就是垃圾收集器的工作重點癞尚。(垃圾回收器的特點參見第3題)

3耸三、(10分)在Java7或8下,簡述Serial浇揩、ParNew仪壮、parallel、cms胳徽、G1,五種垃圾回收器的特點與垃圾回收算法的區(qū)別积锅。針對串行垃圾回收器爽彤、parallel、cms垃圾回收器缚陷,新生代(含from适篙、to區(qū))、老年代的默認內(nèi)存分配比例是箫爷?

答:

垃圾回收器 新生代垃圾收集器(算法) 老年代收集器(算法)
SerialGC Copy / 復(fù)制算法 MarkSweepCompact / 標記壓縮算法
ParNewGC ParNew / 復(fù)制算法 MarkSweepCompact / 標記壓縮算法
ParallelGC PS Scavenge / 復(fù)制算法 PS MarkSweep / 標記整理
ConcMarkSweepGC ParNew / 復(fù)制算法 ConcurrentMarkSweep+serial old / 并發(fā)標記整理+壓縮 +老年代串行垃圾回收
UseG1GC G1 Eden Space(分區(qū)) G1 Old Space(分區(qū))

以上五種垃圾收集器匙瘪,可以出除了G1分區(qū)回收之外,另外四種垃圾回收器都是分代回收的蝶缀。

  1. G1的特點是把堆分成若干個區(qū)丹喻,每次只回收若干個區(qū),用于控制停頓時間翁都。 G1中仍然包含著分代的概念碍论,例如:最大堆是1024m,G1默認1m一個區(qū)柄慰,1024m=1024個區(qū)鳍悠,堆區(qū)數(shù)=新生代區(qū)數(shù)+幸存者區(qū)數(shù)+老年代區(qū)數(shù),1024個=24(新生代)+7(幸存者)+993(老年代)坐搔,對應(yīng)的內(nèi)存容量也是這樣1024m=24m(新生代)+7m(幸存者)+993m(老年代)
    =24(新生代)+7(幸存者)+993(老年代)藏研。
  2. SerialGC 比較適合在cup比較少的場合,性能往往最好概行。
  3. ParNewGC大概就是在串行的基礎(chǔ)上多線程化蠢挡。
  4. ParallelGC和parnew類似,但是Parallelgc更關(guān)注系統(tǒng)的吞吐凳忙,可以根據(jù)吞吐與停頓時間自動調(diào)節(jié)新生代业踏、老年代的使用比例。
  5. 與ParallelGC不同的是ConcMarkSweepGC主要關(guān)注系統(tǒng)停頓涧卵,是一個多線程并行垃圾回收的老年代垃圾回收器勤家,新生代只能與ParNew組合。

串行垃圾回收器柳恐、parallel伐脖、cms垃圾回收器新生代,老年代乐设、from讼庇、to的比例:

SerialGC 新生代:老年代 = \color{red}{1:2} eden:from:to = \color{red}{8:1:1}
ParallelGC 新生代:老年代 = \color{red}{1:2} eden:from:to = \color{red}{6:1:1} 比例可自動調(diào)節(jié)
ConcMarkSweepGC 新生代:老年代 = \color{red}{1:2} eden:from:to = \color{red}{8:1:1}

4、(5分)使用JVM參數(shù)-server -Xms10m -Xmx10m啟動如下程序伤提,是否會出現(xiàn)內(nèi)存溢出或垃圾回收失敗巫俺,為什么?

public static class User{
        public int id =0 ;
        public String name ="";
    }
    public static void alloc(){
        User user = new User();
        user.id=5;
        user.name="manheiba";
    }
    public static void main(String[] args) {
        long b = System.currentTimeMillis();
        for (int i = 0; i < 1000000000; i++) {
            alloc();
        }
        long e = System.currentTimeMillis();
        System.out.println(e-b);
    }

答:不會出現(xiàn)內(nèi)存溢出肿男,因為alloc方法內(nèi)創(chuàng)建的對象會在棧上分配介汹,棧上分配是java虛擬機的一項優(yōu)化技術(shù),它的基本思想是舶沛,對于那些線程私有的對象(這里指不可能被其他線程訪問的對象)嘹承,可以將他們打散分配在棧上,而不是分配在堆上如庭。棧上分配的好處是可以再函數(shù)調(diào)用結(jié)束后自行銷毀叹卷,而不需要垃圾回收器的介入,從而提高系統(tǒng)的性能坪它。對于大量在循環(huán)中創(chuàng)建對象的的服務(wù)器可以開啟棧上分配從而提升系統(tǒng)性能骤竹。棧上分配需要在-server模式下開啟內(nèi)存逃逸分析和標量替換,這兩個參數(shù)默認是打開的往毡。
上面代碼中蒙揣,循環(huán)alloc()方法,在alloc方法中創(chuàng)建對象开瞭,創(chuàng)建的user對象并alloc方法外其他對象引用懒震,java虛擬機會判定user對象不會逃逸,可以棧上分配嗤详,隨著alloc方法執(zhí)行結(jié)束user對象就會被垃圾回收个扰,對象回收的過程不需要垃圾回收器的介入,也不會出現(xiàn)內(nèi)存溢出的情況葱色。

5递宅、(10分)簡述如何觸發(fā)永久代溢出、棧溢出苍狰、java堆溢出恐锣、直接內(nèi)存溢出、創(chuàng)建本地線程溢出以及解決辦法舞痰?

答:

  1. 永久帶是存放class的區(qū)域土榴,可以通過cglib或者asm動態(tài)不停創(chuàng)建class讓永久帶溢出。
  2. 棧上存放棧幀信息响牛,可以通過方法的無限遞歸調(diào)用玷禽,讓棧幀上方法無限增加導(dǎo)致棧溢出。
  3. Java堆溢出:簡單來說循環(huán)中不停創(chuàng)建不被回收的內(nèi)存對象即可導(dǎo)致堆的溢出呀打。
  4. 直接內(nèi)存溢出:可以循環(huán)分配直接內(nèi)存 \color{red}{unsafe.allocateMemory(1024*1024)} 造成直接內(nèi)存溢出矢赁。

6、(5分)簡述類加載器雙親委派模式贬丛?

答:在類加載的時候撩银,系統(tǒng)會判斷當前類是否已經(jīng)加載,如果已經(jīng)被加載豺憔,就會直接返回可用的類额获,否則就會嘗試加載够庙,在嘗試加載時,會先請求雙親處理抄邀,如果雙親請求失敗耘眨,則會自己加載。自定義類加載器的雙親是應(yīng)用類加載器境肾,應(yīng)用類加載器的雙親是擴展類加載器剔难,擴展類加載器的雙親是啟動類加載器。

7奥喻、(10分)簡述解釋執(zhí)行器偶宫、即時編譯器(JIT)在java程序執(zhí)行時的工作流程,為什么有時候Java方法執(zhí)行的比C快 环鲤?

image.png

答:如上圖所示纯趋,class字節(jié)碼會被JVM最后翻譯為計算機可以看懂的機器碼在CUP中運行,這個過程由“解釋執(zhí)行器”進行解釋執(zhí)行楔绞。HotSpot通過循環(huán)回邊計數(shù)器統(tǒng)計熱點方法结闸,即時編譯器會根據(jù)JVM進程的運行時信息(profiler、hprof)進行“編譯優(yōu)化”酒朵,接著把“編譯優(yōu)化”后的熱點方法放在codeCache中桦锄,Java8中默認開啟了分層編譯,方法調(diào)用1500次以下解釋執(zhí)行蔫耽,達到1500次調(diào)用時候調(diào)C1編譯器结耀,達到10000次時調(diào)C2編譯器。C1匙铡、C2編譯后的機器碼執(zhí)行效率更高图甜。通常C2代碼的執(zhí)行效率要比C1高出30%以上。
解釋執(zhí)行相當于同聲傳譯鳖眼,你說一句我翻一句給觀眾(CPU)聽黑毅。JIT是線下翻譯,可以花時間精簡掉你的口語話表達(做編譯優(yōu)化)钦讳。相對比C程序矿瘦, 執(zhí)行java程序時,cpu拿到的是C1愿卒、C2編譯優(yōu)化后的機器碼直接執(zhí)行缚去,所以執(zhí)行效率更快一些。

8琼开、(10分)簡述如下JVM參數(shù)含義:

-XX:+PrintHeapAtGC 打印垃圾回收時的堆信息
-XX:+PrintGCTimeStamps gclog中輸出gc發(fā)生時間
-XX:+PrintGCApplicationStoppedTime 打印GC停頓時間
-Xloggc 指定gclog的文件位置
-XX:HeapDumpPath 指定導(dǎo)出堆文件的文件路徑
-verbose:class 跟蹤類的加載和卸載
-XX:+PrintCommandLineFlags 打印虛擬機顯式和隱式參數(shù)
-Xms 設(shè)置初始堆大小
-Xmx 設(shè)置最大堆大小
-Xmn 設(shè)置新生代大小
-XX:SurvivorRatio 設(shè)置eden/from的比例
-XX:MaxPermSize java7下設(shè)置永久代大小
-XX:MaxDirectMemorySize 設(shè)置直接內(nèi)存大小
–server 設(shè)置為server模式
-XX:+UseConcMarkSweepGC 使用cms垃圾回收器
-XX:CMSInitiatingOccupanyFraction 出發(fā)老年代垃圾回收內(nèi)存占比
-XX:MaxGCPauseMillis 預(yù)期gc停頓時間
-XX:+UseG1GC 使用G1垃圾回收器

9易结、(5分)簡述說明如何寫Java程序來證明STW(Stop-the-world)的這一特性?

答案:編寫java程序,開啟gclog搞动,把jmx設(shè)置的盡量大一些(2G以上躏精,為了讓垃圾收集的時間長一些),選擇串行垃圾回收器滋尉。
在java程序中運行兩個線程:
線程1不斷像HashMap中增加鍵值內(nèi)容玉控,直到老年代打滿的時候進行map.clear()操作飞主。
線程2設(shè)置每隔100ms像控制臺輸出時間戳日志狮惜。
當?shù)诰€程1進行map.clear()后觀察gclog,在gc日志中我們看到了fullgc日志碌识,以及停頓時間碾篡。我們發(fā)現(xiàn),這時候線程2的日志打印的時間戳間隔變長了筏餐,由100毫秒的停頓變成了幾百毫秒的停頓开泽,這個幾百毫秒的停頓與gc日志中的fullgc停頓恰好相符,就是大名鼎鼎的Stop-the-world魁瞪。在STW發(fā)生時穆律,幾乎所有線程掛起,程序像hung死一樣导俘。

10峦耘、(20分)上機題,打開vmware虛擬機旅薄,使用appuser用戶登錄, 密碼: ********辅髓,執(zhí)行腳本./TestStarter.sh
(1)解決啟動時候的報錯,請把調(diào)整后的JVM參數(shù)寫到答題紙上少梁。
(2)成功啟動程序后洛口,結(jié)合linux系統(tǒng)工具、JVM工具分析當前程序中的存在問題及可能的性能瓶頸凯沪。

答:一共5個問題第焰,該題主要是考察結(jié)合工具分析jvm相關(guān)問題,綜合應(yīng)用top妨马、vmstat挺举、iostat、pidstat身笤、jps豹悬、jstat、jinfo液荸、jmap瞻佛、jhat、jstack、jcmd伤柄、hprof绊困、mat、arthas等工具發(fā)現(xiàn)相關(guān)性能問題适刀。(該試題app后面放到github上)
問題1:棾永剩空間不夠。 //增加-xss大小讓程序正常啟動笔喉。
問題2:類加載器造成的死鎖取视。 //使用jstack 觀察線程wait
問題3:存在高cpu線程。 //arthas dashboard觀察高cup線程常挚,jad查看高cpu方法作谭;或者使用查看比較高的線程id轉(zhuǎn)換16進制之后再jstack導(dǎo)出的棧文件中查找導(dǎo)致cpu過高的線程。
問題4:存在大HashMap沒有被正常垃圾回收引發(fā)fullgc的情況奄毡。//使用mat進行分析折欠。
問題5:存在3個線程死鎖問題。 // Jstack -l 查看死鎖

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末吼过,一起剝皮案震驚了整個濱河市锐秦,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌盗忱,老刑警劉巖酱床,帶你破解...
    沈念sama閱讀 218,284評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異售淡,居然都是意外死亡斤葱,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評論 3 395
  • 文/潘曉璐 我一進店門揖闸,熙熙樓的掌柜王于貴愁眉苦臉地迎上來揍堕,“玉大人,你說我怎么就攤上這事汤纸●萌祝” “怎么了?”我有些...
    開封第一講書人閱讀 164,614評論 0 354
  • 文/不壞的土叔 我叫張陵贮泞,是天一觀的道長楞慈。 經(jīng)常有香客問我,道長啃擦,這世上最難降的妖魔是什么囊蓝? 我笑而不...
    開封第一講書人閱讀 58,671評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮令蛉,結(jié)果婚禮上聚霜,老公的妹妹穿的比我還像新娘狡恬。我一直安慰自己,他們只是感情好蝎宇,可當我...
    茶點故事閱讀 67,699評論 6 392
  • 文/花漫 我一把揭開白布弟劲。 她就那樣靜靜地躺著,像睡著了一般姥芥。 火紅的嫁衣襯著肌膚如雪兔乞。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,562評論 1 305
  • 那天凉唐,我揣著相機與錄音庸追,去河邊找鬼。 笑死熊榛,一個胖子當著我的面吹牛锚国,可吹牛的內(nèi)容都是我干的腕巡。 我是一名探鬼主播玄坦,決...
    沈念sama閱讀 40,309評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼绘沉!你這毒婦竟也來了煎楣?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,223評論 0 276
  • 序言:老撾萬榮一對情侶失蹤车伞,失蹤者是張志新(化名)和其女友劉穎择懂,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體另玖,經(jīng)...
    沈念sama閱讀 45,668評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡困曙,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,859評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了谦去。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片慷丽。...
    茶點故事閱讀 39,981評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖鳄哭,靈堂內(nèi)的尸體忽然破棺而出要糊,到底是詐尸還是另有隱情,我是刑警寧澤妆丘,帶...
    沈念sama閱讀 35,705評論 5 347
  • 正文 年R本政府宣布锄俄,位于F島的核電站,受9級特大地震影響勺拣,放射性物質(zhì)發(fā)生泄漏奶赠。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,310評論 3 330
  • 文/蒙蒙 一药有、第九天 我趴在偏房一處隱蔽的房頂上張望毅戈。 院中可真熱鬧,春花似錦、人聲如沸竹祷。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽塑陵。三九已至感憾,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間令花,已是汗流浹背阻桅。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留兼都,地道東北人嫂沉。 一個月前我還...
    沈念sama閱讀 48,146評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像扮碧,于是被迫代替她去往敵國和親趟章。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,933評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 這篇文章是我之前翻閱了不少的書籍以及從網(wǎng)絡(luò)上收集的一些資料的整理慎王,因此不免有一些不準確的地方蚓土,同時不同JDK版本的...
    高廣超閱讀 15,604評論 3 83
  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴謹 對...
    cosWriter閱讀 11,101評論 1 32
  • 所有知識點已整理成app app下載地址 J2EE 部分: 1.Switch能否用string做參數(shù)? 在 Jav...
    侯蛋蛋_閱讀 2,434評論 1 4
  • 《深入理解Java虛擬機》筆記_第一遍 先取看完這本書(JVM)后必須掌握的部分赖淤。 第一部分 走近 Java 從傳...
    xiaogmail閱讀 5,093評論 1 34
  • 第二部分 自動內(nèi)存管理機制 第二章 java內(nèi)存異常與內(nèi)存溢出異常 運行數(shù)據(jù)區(qū)域 程序計數(shù)器:當前線程所執(zhí)行的字節(jié)...
    小明oh閱讀 1,164評論 0 2