JAVA基礎(chǔ)整理

1.JVM為什么可以跨平臺(tái)

JVM能跨計(jì)算機(jī)體系結(jié)構(gòu)(操作系統(tǒng))來(lái)執(zhí)行Java字節(jié)碼(JVM字節(jié)碼指令集),屏蔽可與各個(gè)計(jì)算機(jī)平臺(tái)相關(guān)的軟件或者硬件之間的差異,使得與平臺(tái)相關(guān)的耦合統(tǒng)一由JVM提供者來(lái)實(shí)現(xiàn)。

指令集:計(jì)算機(jī)所能識(shí)別的機(jī)器語(yǔ)言的命令集合。

每個(gè)運(yùn)行中的Java程序都是一個(gè)JVM實(shí)例。

2.描述JVM體系結(jié)構(gòu)

(1)類加載器:JVM啟動(dòng)時(shí)或者類運(yùn)行時(shí)將需要的class加載到JVM中。每個(gè)被裝載的類的類型對(duì)應(yīng)一個(gè)Class實(shí)例,唯一表示該類,存于堆中。

(2)執(zhí)行引擎:負(fù)責(zé)執(zhí)行JVM的字節(jié)碼指令(CPU)。執(zhí)行引擎是JVM的核心部分,作用是解析字節(jié)碼指令,得到執(zhí)行結(jié)果(實(shí)現(xiàn)方式:直接執(zhí)行,JIT(just in time)即時(shí)編譯轉(zhuǎn)成本地代碼執(zhí)行,寄存器芯片模式執(zhí)行,基于棧執(zhí)行)。本質(zhì)上就是一個(gè)個(gè)方法串起來(lái)的流程。每個(gè)Java線程就是一個(gè)執(zhí)行引擎的實(shí)例,一個(gè)JVM實(shí)例中會(huì)有多個(gè)執(zhí)行引擎在工作,有的執(zhí)行用戶程序,有的執(zhí)行JVM內(nèi)部程序(GC).

(3)內(nèi)存區(qū):模擬物理機(jī)的存儲(chǔ)、記錄和調(diào)度等功能模塊,如寄存器或者PC指針記錄器。存儲(chǔ)執(zhí)行引擎執(zhí)行時(shí)所需要存儲(chǔ)的數(shù)據(jù)。

(4)本地方法接口:調(diào)用操作系統(tǒng)本地方法返回結(jié)果。

3.描述JVM工作機(jī)制

機(jī)器如何執(zhí)行代碼:源代碼-預(yù)處理器-編譯器-匯編程序-目標(biāo)代碼-鏈接器-可執(zhí)行程序。

Java編譯器將高級(jí)語(yǔ)言編譯成虛擬機(jī)目標(biāo)語(yǔ)言。

JVM執(zhí)行字節(jié)碼指令是基于棧的架構(gòu),所有的操作數(shù)必須先入棧,然后根據(jù)操作碼選擇從棧頂彈出若干元素進(jìn)行計(jì)算后將結(jié)果壓入棧中。

通過(guò)Java編譯器將源代碼編譯成虛擬機(jī)目標(biāo)語(yǔ)言,然后通過(guò)JVM執(zhí)行引擎執(zhí)行。

4.為何JVM字節(jié)碼指令選擇基于棧的結(jié)構(gòu)

JVM要設(shè)計(jì)成平臺(tái)無(wú)關(guān)性,很難設(shè)計(jì)統(tǒng)一的基于寄存器的指令。

為了指令的緊湊性,讓編譯后的class文件更加緊湊,提高字節(jié)碼在網(wǎng)絡(luò)上的傳輸效率。

5.描述執(zhí)行引擎的架構(gòu)設(shè)計(jì)

創(chuàng)建新線程時(shí),JVM會(huì)為這個(gè)線程創(chuàng)建一個(gè)棧,同時(shí)分配一個(gè)PC寄存器(指向第一行可執(zhí)行的代碼)。調(diào)用新方法時(shí)會(huì)在這個(gè)棧上創(chuàng)建新的棧幀數(shù)據(jù)結(jié)構(gòu)。執(zhí)行完成后方法對(duì)應(yīng)的棧幀將消失,PC寄存器被銷毀,局部變量區(qū)所有值被釋放,被JVM回收。

6. 描述javac編譯器的基本結(jié)構(gòu)

Javac編譯器的作用是將符合Java語(yǔ)言規(guī)范的的源代碼轉(zhuǎn)換成JVM規(guī)范的Java字節(jié)碼。

(1)詞法分析器組件:找出規(guī)范化的Token流

(2)語(yǔ)法分析器組件:生成符合Java語(yǔ)言規(guī)范的抽象語(yǔ)法樹

(3)語(yǔ)義分析器組件:將復(fù)雜的語(yǔ)法轉(zhuǎn)化成最簡(jiǎn)單的語(yǔ)法,注解語(yǔ)法樹

(4)代碼生成器組件:將語(yǔ)法樹數(shù)據(jù)結(jié)構(gòu)轉(zhuǎn)化成字節(jié)碼數(shù)據(jù)結(jié)構(gòu)

7.描述JVM編譯優(yōu)化

早期(編譯器):

很少;編譯時(shí),為節(jié)省常量池空間,能確定的相同常量只用一個(gè)引用地址。

晚期(運(yùn)行期):

方法內(nèi)聯(lián):去除方法調(diào)用的成本;為其他優(yōu)化建立良好基礎(chǔ),便于在更大范圍采取連續(xù)優(yōu)化的手段。

冗余訪問(wèn)消除:公共子表達(dá)式消除

復(fù)寫傳播:完全相等的變量可替代

無(wú)用代碼消除:清除永遠(yuǎn)不會(huì)執(zhí)行的代碼

? ? ? (1)公共子表達(dá)式消除(語(yǔ)言無(wú)關(guān)):如果公共子表達(dá)式已經(jīng)計(jì)算過(guò)了,并且沒(méi)有變化,那就沒(méi)有必要再次計(jì)算,可用結(jié)果替換。

? ? ? (2)數(shù)組邊界檢查消除(語(yǔ)言相關(guān)):限定循環(huán)變量在取值范圍之間,可節(jié)省多次條件判斷。

? ? ? (3)方法內(nèi)聯(lián)(最重要):去除方法調(diào)用的成本;為其他優(yōu)化建立良好基礎(chǔ),便于在更大范圍采取連續(xù)優(yōu)化的手段。

? ? ? (4)逃逸分析(最前沿):分析對(duì)象的動(dòng)態(tài)作用域;變量作為調(diào)用參數(shù)傳遞到其他方法中-方法逃逸;被外部線程訪問(wèn)-線程逃逸。

棧上分配-減少垃圾系統(tǒng)收集壓力

同步消除-如果無(wú)法逃逸出線程,則可以消除同步

標(biāo)量替換-將變量恢復(fù)原始類型來(lái)訪問(wèn)

小抄:final修飾的局部變量和參數(shù),在常量池中沒(méi)有符號(hào)引用,沒(méi)有訪問(wèn)標(biāo)識(shí),對(duì)運(yùn)行期是沒(méi)有任何影響的,僅僅保證其編譯期間的不變性。

8.ClassLoader(類加載器)有哪些

(1)Bootstrap ClassLoader(啟動(dòng)類加載器):完全由JVM控制,加載JVM自身工作需要的類(JAVA_HOME/lib)

(2)Extension ClassLoader(擴(kuò)展類加載器):屬于JVM自身一部分,不是JVM自身實(shí)現(xiàn)的(JAVA_HOME/lib/ext)

(3)Appclication ClassLoader(應(yīng)用程序類加載器):父類是Extension ClassLoader,加載Classpath(用戶類路徑)上的類庫(kù)

9.描述ClassLoader的作用(什么是類加載器)和加載過(guò)程

將Class文件加載到JVM中、審查每個(gè)類由誰(shuí)加載(父優(yōu)先的等級(jí)加載機(jī)制)、將Class字節(jié)碼重新解析成JVM統(tǒng)一要求的對(duì)象(Class對(duì)象)格式。

.class->findclass->Liking:Class規(guī)范驗(yàn)證、準(zhǔn)備、解析->類屬性初始化賦值(static塊的執(zhí)行)->Class對(duì)象(這也就是為什么靜態(tài)塊只執(zhí)行一次)

10.描述JVM類加載機(jī)制

ClassLoader首先不會(huì)自己嘗試去加載類,而是把這個(gè)請(qǐng)求委托給父類加載器完成,每一個(gè)層次都是。只有當(dāng)父加載器反饋無(wú)法完成請(qǐng)求時(shí)(在搜索范圍內(nèi)沒(méi)有找到所需的類),子加載器才會(huì)嘗試加載(等級(jí)加載機(jī)制、父優(yōu)先、雙親委派)。

好處:類隨著它的加載器一起具有一種帶有優(yōu)先級(jí)的層次關(guān)系;保證同一個(gè)類只能被一個(gè)加載器加載。

11.JVM加載class文件到內(nèi)存的兩種方式

(1)隱式加載:繼承或者引用的類不在內(nèi)存中

(2)顯式加載:代碼中通過(guò)調(diào)用ClassLoader加載

12.加載類錯(cuò)誤分析及其解決

(1)ClassNotFoundException:沒(méi)有找到對(duì)應(yīng)的字節(jié)碼(.class)文件;檢查classpath下有無(wú)對(duì)應(yīng)文件

(2)NoClassDefFoundError:隱式加載時(shí)沒(méi)有找到,ClassNotFoundException引發(fā)NoClassDefFoundError;確保每個(gè)類引用的類都在classpath下

(3)UnsatisfiedLinkError:(未滿足鏈接錯(cuò)誤)刪除了JVM的某個(gè)lib文件或者解析native標(biāo)識(shí)的方法時(shí)找不到對(duì)應(yīng)的本地庫(kù)文件

(4)ClassCastException:強(qiáng)制類型轉(zhuǎn)換時(shí)出現(xiàn)這個(gè)錯(cuò)誤;容器類型最好顯示指明其所包含對(duì)象類型、先instanceof檢查是不是目標(biāo)類型,再類型轉(zhuǎn)換

(5)ExceptionInitializerError:給類的靜態(tài)屬性賦值時(shí)

13:Java應(yīng)不應(yīng)該動(dòng)態(tài)加載類(JVM能不能動(dòng)態(tài)加載類)

JVM中對(duì)象只有一份,不能被替換,對(duì)象的引用關(guān)系只有對(duì)象的創(chuàng)建者持有和使用,JVM不可干預(yù)對(duì)象的引用關(guān)系,因?yàn)镴VM不知道對(duì)象是怎么被使用的,JVM不知道對(duì)象的運(yùn)行時(shí)類型,只知道編譯時(shí)類型。

但是可以不保存對(duì)象的狀態(tài),對(duì)象創(chuàng)建和使用后就被釋放掉,下次修改后,對(duì)象就是新的了(JSP)。

14.Java中哪些組件需要使用內(nèi)存

(1)Java堆:存儲(chǔ)Java對(duì)象

(2)線程:Java運(yùn)行程序的實(shí)體

(3)類和類加載器:存儲(chǔ)在堆中,這部分區(qū)域叫永久代(PermGen區(qū))

(4)NIO:基于通道和緩沖區(qū)來(lái)執(zhí)行I/O的新方式。

(5)JNI:本地代碼可以調(diào)用Java方法,Java方法也可以調(diào)用本地代碼

15.描述JVM內(nèi)存結(jié)構(gòu)及內(nèi)存溢出。

JVM是按照運(yùn)行時(shí)數(shù)據(jù)的存儲(chǔ)結(jié)構(gòu)來(lái)劃分內(nèi)存結(jié)構(gòu)的。

PC寄存器數(shù)據(jù):嚴(yán)格來(lái)說(shuō)是一個(gè)數(shù)據(jù)結(jié)構(gòu),保存當(dāng)前正在執(zhí)行的程序的內(nèi)存地址。為了線程切換后能恢復(fù)到正確的執(zhí)行位置,線程私有。不會(huì)內(nèi)存溢出。

(1)Java棧:方法執(zhí)行的內(nèi)存模型,存儲(chǔ)線程執(zhí)行所需要的數(shù)據(jù)。線程私有。

--OutOfMemoryError:JVM擴(kuò)展棧時(shí)無(wú)法申請(qǐng)到足夠的空間。一個(gè)不斷調(diào)用自身而不會(huì)終止的方法。

--StackOverflowError:請(qǐng)求的棧深度大于JVM所允許的棧深度。創(chuàng)建足夠多的線程。

(2)堆:存儲(chǔ)對(duì)象,每一個(gè)存在堆中Java對(duì)象都是這個(gè)對(duì)象的類的副本,復(fù)制包括繼承自他父類的所有非靜態(tài)屬性。線程共享。

--OutOfMemoryError:對(duì)象數(shù)量到達(dá)堆容量限制??赏ㄟ^(guò)不斷向ArrayList中添加對(duì)象實(shí)現(xiàn)。

(3)方法區(qū):存儲(chǔ)類結(jié)構(gòu)信息。包括常量池(編譯期生產(chǎn)的各種字面量和符號(hào)引用)和運(yùn)行時(shí)常量池。線程共享。

--OutOfMemoryError:同運(yùn)行時(shí)常量池。

(4)本地方法棧:與Java棧類似,為JVM運(yùn)行Native方法準(zhǔn)備的空間。線程私有。(C棧)OutOfMemoryError和StackOverflowError同JVM棧。

(5)運(yùn)行時(shí)常量池:代表運(yùn)行時(shí)每個(gè)class文件中的常量表。運(yùn)行期間產(chǎn)生的新的常量放入運(yùn)行時(shí)常量池。

--OutOfMemoryError:不斷向List中添加字符串,然后String.inern(),PermGen Space(運(yùn)行時(shí)常量池屬于方法區(qū))。

(6)本地直接內(nèi)存:即NIO。

--OutOfMemoryError:通過(guò)直接向操作系統(tǒng)申請(qǐng)分配內(nèi)存。

16.描述JVM內(nèi)存分配策略

(1)對(duì)象優(yōu)先分配在Eden

(2)大對(duì)象直接進(jìn)入老年代

(3)長(zhǎng)期存活的對(duì)象將進(jìn)入老年代

(4)幸存區(qū)相同年齡對(duì)象的占幸存區(qū)空間的多于其一半,將進(jìn)入老年代

(5)空間擔(dān)保分配(老年代剩余空間需多于幸存區(qū)的一半,否則要Full GC)

17.描述JVM如何檢測(cè)垃圾

通過(guò)可達(dá)性分析算法,通過(guò)一些列稱為GC Roots的對(duì)象作為起始點(diǎn),從這些起始點(diǎn)向下搜索,搜索所走過(guò)的路徑稱為引用鏈,當(dāng)一個(gè)對(duì)象到GC Roots沒(méi)有任何引用鏈相連(GC Roots到這個(gè)對(duì)象不可達(dá)),則證明這個(gè)對(duì)象是不可用的。

使用可達(dá)性分析算法而不是引用計(jì)數(shù)算法。因?yàn)橐糜?jì)數(shù)算法很難解決對(duì)象之間相互循環(huán)引用的問(wèn)題。

18.哪些元素可作為GC Roots

(1)JVM棧(棧幀中的本地變量表)中的引用

(2)方法區(qū)中類靜態(tài)屬性引用

(3)方法區(qū)中常量引用

(4)本地方法棧中JNI(一般的Native方法)引用

19.描述分代垃圾收集算法的思路:

把對(duì)象按照壽命長(zhǎng)短來(lái)分組,分為年輕代和老年代,新創(chuàng)建的在老年代,經(jīng)歷幾次回收后仍然存活的對(duì)象進(jìn)入老年代,老年代的垃圾頻率不像年輕代那樣頻繁,減少每次收集都去掃描所有對(duì)象的數(shù)量,提高垃圾回收效率。

20.描述基于分代的堆結(jié)構(gòu)及其比例。

(1)年輕代(Young區(qū)-1/4):Eden+Survior(1/8,這個(gè)比例保證只有10%的空間被浪費(fèi),保證每次回收都只有不多于10%的對(duì)象存活)=From+To,存放新創(chuàng)建的對(duì)象.

(2)老年代(Old區(qū) ):存放幾次垃圾收集后存活的對(duì)象

(3)永久區(qū)(Perm區(qū)):存放類的Class對(duì)象

21.描述垃圾收集算法

(1)標(biāo)記-清除算法:首先標(biāo)記處所要回收的對(duì)象,標(biāo)記完成后統(tǒng)一清除。缺點(diǎn):標(biāo)記效率低,清除效率低,回收結(jié)束后會(huì)產(chǎn)生大量不連續(xù)的內(nèi)存碎片(沒(méi)有足夠連續(xù)空間分配內(nèi)存,提前觸發(fā)另一次垃圾回收)。適用于對(duì)象存活率高的老年代。

(2)復(fù)制算法(Survivor的from和to區(qū),from和to會(huì)互換角色):

將內(nèi)存容量劃分大小相等的兩塊,每次只使用其中一塊。一塊用完,就將存活的對(duì)象復(fù)制到另一塊,然后把使用過(guò)的一塊一次清除。不用考慮內(nèi)存碎片,每次只要移動(dòng)頂端指針,按順序分配內(nèi)存即可,實(shí)現(xiàn)簡(jiǎn)單運(yùn)行高效。適用于新生代。

缺點(diǎn):內(nèi)存縮小為原來(lái)的一般,代價(jià)高。浪費(fèi)50%的空間。

(3)標(biāo)記-整理算法:

標(biāo)記完成后,將存活的對(duì)象移動(dòng)到一端,然后清除邊界以外的內(nèi)存。適用于對(duì)象存活率高的老年代。

22.描述新生代和老年代的回收策略

Eden區(qū)滿后觸發(fā)minor GC,將所有存活對(duì)象復(fù)制到一個(gè)Survivor區(qū),另一Survivor區(qū)存活的對(duì)象也復(fù)制到這個(gè)Survivor區(qū)中,始終保證有一個(gè)Survivor是空的。

Toung區(qū)Survivor滿后觸發(fā)minor GC后仍然存活的對(duì)象存到Old區(qū),如果Survivor區(qū)放不下Eden區(qū)的對(duì)象或者Survivor區(qū)對(duì)象足夠老了,直接放入Old區(qū),如果Old區(qū)放不下則觸發(fā)Full GC。

Perm區(qū)滿將觸發(fā)Major GC。

23.描述CMS垃圾收集器

CMS 收集器:Concurrent Mark Sweep 并發(fā)標(biāo)記-清除。重視響應(yīng)速度,適用于互聯(lián)網(wǎng)和B/S系統(tǒng)的服務(wù)端上。初始標(biāo)記還是需要Stop the world 但是速度很快。缺點(diǎn):CPU資源敏感,無(wú)法浮動(dòng)處理垃圾,會(huì)有大量空間碎片產(chǎn)生。

24.Java應(yīng)不應(yīng)該動(dòng)態(tài)記載類

Java的優(yōu)勢(shì)正是基于共享對(duì)象的機(jī)制,達(dá)到信息的高度共享,也就是通過(guò)保存并持有對(duì)象的狀態(tài)而省去類信息的重復(fù)創(chuàng)建和回收。對(duì)象一旦被創(chuàng)建,就可以被人持有和利用。動(dòng)態(tài)加載理論上可以直接替換這個(gè)對(duì)象,然后更新Java棧中所有對(duì)原對(duì)象的引用關(guān)系,但是仍然不可行,因?yàn)檫@違反了JVM的設(shè)計(jì)原則,對(duì)象的引用只有對(duì)象的創(chuàng)建者持有和使用,JVM并不可以干預(yù)對(duì)象的引用關(guān)系,因?yàn)镴VM并不知道對(duì)象是怎么辦使用的,JVM并不知道對(duì)象的運(yùn)行時(shí)類型而只知道編譯時(shí)類型。

假如一個(gè)對(duì)象的屬性結(jié)構(gòu)被修改,但在運(yùn)行時(shí)其他對(duì)象可能仍然引用該屬性。

但是可以采取不保存對(duì)象的狀態(tài)的解決辦法,對(duì)象被創(chuàng)建后使用后就被釋放掉,下次修改后,對(duì)象也就是新的了。JSP和其他解釋型語(yǔ)言都是如此。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容