1)Java內(nèi)存模型

????程序計數(shù)器:當(dāng)前執(zhí)行的字節(jié)碼行號指示器,字節(jié)碼指示器就根據(jù)這個計數(shù)器的值來選取下一條指令,分支、循環(huán)、跳轉(zhuǎn)、異常處理、線程恢復(fù)等基礎(chǔ)功能都要依賴這個計數(shù)器來完成。是Java虛擬機內(nèi)存規(guī)范中唯一一個沒有規(guī)定任何OutOfMemoryError區(qū)域。
????本地方法棧:不是用Java語言寫的,而是用C/C++編寫的本地方法。它相當(dāng)于一個接口,方便與Java環(huán)境外部和操作系統(tǒng)的交互。
????虛擬機棧:為虛擬機執(zhí)行Java方法服務(wù)。每個方法在執(zhí)行的同時,創(chuàng)建一個棧幀,用于存儲局部變量表、動態(tài)鏈接、方法出口等信息。每一個方法從調(diào)用到結(jié)束的過程對應(yīng)的就是一個棧幀在虛擬機中入棧和出棧的過程。
????方法區(qū):所有Java線程共享的一塊兒內(nèi)存區(qū)域,用于存儲已被虛擬機加載的類信息、常量、靜態(tài)變量部分、即時編譯器編譯之后的代碼等數(shù)據(jù)。
????堆:被所有Java線程共享的區(qū)域,存放Java對象實例和數(shù)組,是垃圾回收的主要區(qū)域。
????運行時的常量池:方法區(qū)的一部分,用于存放編譯器生成的各種字面量和符號引用,將在類加載后放到常量池中。
????面試題:String str = new String("abc")內(nèi)存如何分配?答:str是棧內(nèi)變量,它的內(nèi)存保存的是堆中的new String對象的地址,new String在堆中生成對象,并用常量池的字符串對象"abc"初始化堆中的對象。
????面試題:虛擬機棧和本地方法棧的區(qū)別是什么?答:二者發(fā)揮的作用非常相似,區(qū)別是虛擬機棧為虛擬機執(zhí)行Java方法服務(wù),而本地方法棧則為執(zhí)行虛擬機使用到的Native方法服務(wù),與虛擬機棧一樣,本地方法棧也會拋出StackOverFlow和OutOfMemoryError異常。
????面試題:說下String.intern()?答:String.inern()是一個Native方法,它的作用是:如果字符串常量池中已經(jīng)包含一個等于此Strig對象的字符串,則返回代表池中這個字符串的String對象,否則,將此String對象包含的字符串添加到常量池中,并返回此String對象的引用。
2)垃圾收集算法
????如何判斷對象是否存活?采用可達性分析來判斷對象是否存活的?;舅悸肥牵和ㄟ^一系列的GC Roots作為起始點,向下搜索,看是否可以到達其他對象。不可到達就是可以回收的對象。如下圖所示:其中,雖然Objects3和Obejects4是相連的,但是他們與GC Roots并沒有相連,所以是可以回收的對象。

????面試題:說下強引用、軟引用、弱引用和幻象引用有什么區(qū)別?答:不同的引用類型,主要體現(xiàn)的是對象不同的可達性狀態(tài)和對垃圾收集的影響。強引用,new出來的對象都是強引用,只要有強引用指向一個對象,證明該對象還活著,除非將其顯示地賦值為null,就可以被垃圾收集了;軟引用:比強引用弱一些的引用,當(dāng)JVM認(rèn)為內(nèi)存不足時,就會試圖去回收軟引用指向的對象。JVM會確保在拋出OutOfMemoryError之前,清理軟引用指向的對象。弱引用:強度比軟引用更弱一些,他只能生存到下一次垃圾回收之前。當(dāng)垃圾收集器工作時,無論當(dāng)前內(nèi)存是否充足,都會回收只被弱引用關(guān)聯(lián)的對象?;孟笠茫阂步刑撘?,無法通過他獲得對象實例,設(shè)置他的唯一目的是在這個對象被收集器回收時收到一個系統(tǒng)通知,有人利用幻象引用的對象進行監(jiān)控對象的創(chuàng)建和銷毀。
????垃圾收集算法:有標(biāo)記-清除算法、復(fù)制算法、標(biāo)記-整理算法和分代收集算法。標(biāo)記-清除算法:顧名思義,就是先標(biāo)記再清除,把要回收的進行標(biāo)記然后統(tǒng)一清除。缺點:效率低和產(chǎn)生大量不連續(xù)的空間碎片。復(fù)制算法:把內(nèi)存分為大小相等的兩塊,每次只用一塊,這塊用完了就把存活的對象復(fù)制到另一塊上,缺點是內(nèi)存縮小了原來的一半。現(xiàn)代的商業(yè)虛擬機都采用這種算法進行垃圾回收,但是不是分為大小相等的兩塊,而是分為一塊較大的Eden和兩塊較小的Survivor區(qū)域,每次使用一塊Eden和Survivor區(qū)域,把存活的復(fù)制到另外一塊Survivor區(qū)域,然后清理剛才使用的Eden和Survivor。標(biāo)記-整理算法:標(biāo)記要回收的對象,讓存活的對象向一端移動,然后清理掉端外的對象。分代收集算法:當(dāng)代虛擬機都采用這種垃圾收集算法,新生代采用復(fù)制算法,老年代采用標(biāo)記-清理或者標(biāo)記-整理算法。
3)垃圾收集器
????Serial收集器:虛擬機在Client模式下默認(rèn)的垃圾收集器,是單線程收集器,在他進行垃圾回收的時候必須暫停其他所有的工作線程,直到其收集完畢。
????ParNew收集器:是Serial收集器的多線程版本,是許多運行在Server模式下的虛擬機中首選的新生代收集器,只有他能與CMS配合工作。
????Parallel Scavenge收集器:是一個新生代收集器,是并行的多線程收集器,他的主要目的是達到一個可控制的吞吐量(吞吐量=運行用戶代碼時間/(運行用戶代碼時間+垃圾收集時間))。
????Serial Old收集器:是Serial收集器老年代的并發(fā)版本,同樣是一個單線程收集器,使用標(biāo)記-整理算法。
????Parallel Old收集器:是Parallel Scavenge收集器的老年代版本,使用多線程和標(biāo)記-整理算法。
????CMS收集器:Concurrent mark sweep收集器,使用標(biāo)記-清除算法,關(guān)注點事停頓時間短,主要包含四個步驟:
????1. 初始標(biāo)記:標(biāo)記一下GC Roots能直接關(guān)聯(lián)到的對象,速度快,需要“Stop the world”;
????2. 并發(fā)標(biāo)記:進行GC Roots Tracing的過程,不停頓;
????3. 重新標(biāo)記:為了修正并發(fā)標(biāo)記的時候,因用戶程序繼續(xù)運行而導(dǎo)致標(biāo)記產(chǎn)生變動的那一部分對象的標(biāo)記記錄,需要停頓;
????4. 并發(fā)清除:不需要停頓。
????缺點:對CPU資源非常敏感,無法處理浮動垃圾,有大量的空間碎片產(chǎn)生,容易引發(fā)FullGC。
????G1收集器:兼顧了吞吐量和停頓時間的收集器,是面向服務(wù)端應(yīng)用的垃圾收集器,是JDK9以后默認(rèn)的GC選項,在JKD9中,CMS被標(biāo)記為廢棄的(deprecated)。大致分為以下四個步驟:
????1. 初始標(biāo)記:標(biāo)記一下GC Roots能直接關(guān)聯(lián)到的對象,速度快,需要停頓;
????2. 并發(fā)標(biāo)記:從GC Root開始對堆中對象進行可達性分析,找出存活的對象,這步驟耗時長,但可與用戶程序并發(fā)執(zhí)行;
????3. 最終標(biāo)記:為了修正在并發(fā)標(biāo)記的時候,因用戶程序繼續(xù)運行而導(dǎo)致標(biāo)記產(chǎn)生變動的那一部分對象的標(biāo)記記錄,虛擬機將這段時間對象變化記錄在線程的 Remembered Set Logs 里面,最終標(biāo)記階段需要把 Remembered Set Logs 的數(shù)據(jù)合并到 Remembered Set 中。需要停頓,但可并行執(zhí)行;
????4. 篩選回收:首先對各個 Region 中的回收價值和成本進行排序,根據(jù)用戶所期望的 GC 停頓時間來制定回收計劃。此階段其實也可以做到與用戶程序一起并發(fā)執(zhí)行,但是因為只回收一部分 Region,時間是用戶可控制的,而且停頓用戶線程將大幅度提高收集效率。
注:主要參考《深入理解Java虛擬機_JVM高級特性與最佳實戰(zhàn)》周志明