1 JVM組成結(jié)構(gòu)?
JVM = 類加載器(classloader) + 執(zhí)行引擎(execution engine) + 運行時數(shù)據(jù)區(qū)域(runtime data area)
2 JVM運行時數(shù)據(jù)區(qū)域岩睁?
3 什么是程序計數(shù)器钞脂?
- 當(dāng)前線程所執(zhí)行的字節(jié)碼的行號指示器;
- 線程私有捕儒,生命周期與線程相同冰啃;
- 在虛擬機的概念模型里邓夕,字節(jié)碼解釋器工作時就是 通過改變這個計數(shù)器的值來選取下一條需要執(zhí)行的字節(jié)碼指令,如:分支阎毅、循環(huán)焚刚、跳轉(zhuǎn)、異常處理扇调、線程恢復(fù)(多線程切換)等基礎(chǔ)功能矿咕;
- 如果線程正在執(zhí)行的是一個Java方法,這個計數(shù)器記錄的是正在執(zhí)行的虛擬機字節(jié)碼指令的地址狼钮;如果正在執(zhí)行的是Natvie方法痴腌,這個計數(shù)器值則為空(undefined);
- 程序計數(shù)器中存儲的數(shù)據(jù)所占空間的大小不會隨程序的執(zhí)行而發(fā)生改變燃领,所以此區(qū)域不會出現(xiàn)OutOfMemoryError的情況;
4 什么是虛擬機棧锦援?
- 描述的是Java方法執(zhí)行的內(nèi)存模型猛蔽,每個方法被執(zhí)行的時候都會同時創(chuàng)建一個 棧幀(Stack Frame) 用于存儲 局部變量表、操作棧灵寺、動態(tài)鏈接曼库、方法出口 等信息。每一個方法被調(diào)用直至執(zhí)行完成的過程略板,就對應(yīng)著一個棧幀在虛擬機棧中從入棧到出棧的過程毁枯。
- 線程私有,生命周期與線程相同叮称;
- 局部變量表存放了編譯期可知的各種基本數(shù)據(jù)類型(boolean种玛、byte、char瓤檐、short赂韵、int、float挠蛉、long祭示、double)、對象引用(reference類型)谴古;它不等同于對象本身质涛,根據(jù)不同的虛擬機實現(xiàn),它可能是一個指向?qū)ο笃鹗嫉刂返囊弥羔橁#部赡苤赶蛞粋€代表對象的句柄或者其他與此對象相關(guān)的位置)和returnAddress類型(指向了一條字節(jié)碼指令的地址)汇陆。局部變量表所需的內(nèi)存空間在編譯期間完成分配,當(dāng)進入一個方法時恩敌,這個方法需要在棧幀中分配多大的局部變量空間是完全確定的瞬测,在方法運行期間不會改變局部變量表的大小。
- 該區(qū)域可能拋出以下異常:
- 當(dāng)線程請求的棧深度超過最大值,會拋出 StackOverflowError 異常月趟;
- 棧進行動態(tài)擴展時如果無法申請到足夠內(nèi)存灯蝴,會拋出 OutOfMemoryError 異常;
5 什么是本地方法棧孝宗?
- 為虛擬機使用到的 Native 方法服務(wù)穷躁;
- 線程私有,生命周期與線程相同因妇;
- 虛擬機規(guī)范中對本地方法棧中的方法使用的語言问潭、使用的方式與數(shù)據(jù)結(jié)構(gòu)并沒有強制規(guī)定,因此具體的虛擬機可以自由實現(xiàn)它婚被。甚至有的虛擬機(譬如Sun HotSpot 虛擬機)直接就把本地方法棧和虛擬機棧合二為一狡忙;
- 與虛擬機棧一樣,本地方法棧區(qū)域也會拋出StackOverflowError和OutOfMemoryError異常址芯;
6 什么是堆灾茁?
- 在虛擬機啟動時創(chuàng)建,用來存放對象實例谷炸,幾乎所有的對象實例都在這里分配內(nèi)存北专;
- 被所有線程共享;
- Java堆是垃圾收集器管理的主要區(qū)域旬陡,因此很多時候也被稱做“GC堆”拓颓。如果從內(nèi)存回收的角度看,由于現(xiàn)在收集器基本都是 采用的分代收集算法描孟,所以Java堆中還可以細(xì)分為:新生代和老年代驶睦;新生代又有Eden空間、From Survivor空間画拾、To Survivor空間三部分啥繁;
- Java 堆不需要連續(xù)內(nèi)存,并且可以通過動態(tài)增加其內(nèi)存青抛,增加失敗會拋出 OutOfMemoryError 異常旗闽;
7 什么是方法區(qū)?
- 用于存放 已被加載的類信息蜜另、常量适室、靜態(tài)變量、即時編譯器編譯后的代碼 等數(shù)據(jù)举瑰;
- 被所有線程共享捣辆;
- 對這塊區(qū)域進行垃圾回收的主要目標(biāo)是 對常量池的回收和對類的卸載,但是一般比較難實現(xiàn)此迅,HotSpot 虛擬機把它當(dāng)成永久代(Permanent Generation)來進行垃圾回收汽畴;
- 和 Java 堆一樣不需要連續(xù)的內(nèi)存旧巾,并且可以動態(tài)擴展,動態(tài)擴展失敗一樣會拋出 OutOfMemoryError 異常忍些;
8 什么是運行時常量池鲁猩?
- 運行時常量池是方法區(qū)的一部分;
- Class 文件中的常量池(編譯器生成的各種字面量和符號引用)會在類加載時被放入這個區(qū)域罢坝;
- 除了 在編譯期生成的常量廓握,還允許動態(tài)生成,例如 String 類的 intern()嘁酿。這部分常量也會被放入運行時常量池隙券;
在 JDK1.7之前,HotSpot 使用永久代實現(xiàn)方法區(qū)闹司;HotSpot 使用 GC 分代實現(xiàn)方法區(qū)帶來了很大便利娱仔;
從 JDK1.7 開始 HotSpot 開始移除永久代。其中符號引用(Symbols)被移動到 Native Heap中游桩,字符串常量和類引用被移動到 Java Heap中拟枚。
在 JDK1.8 中,永久代已完全被元空間(Meatspace)所取代众弓。元空間的本質(zhì)和永久代類似,都是對JVM規(guī)范中方法區(qū)的實現(xiàn)隔箍。不過元空間與永久代之間最大的區(qū)別在于:元空間并不在虛擬機中谓娃,而是使用本地內(nèi)存。因此蜒滩,默認(rèn)情況下滨达,元空間的大小僅受本地內(nèi)存限制。
9 什么是直接內(nèi)存俯艰?
- 直接內(nèi)存(Direct Memory)并不是虛擬機運行時數(shù)據(jù)區(qū)的一部分捡遍,也不是Java虛擬機規(guī)范中定義的內(nèi)存區(qū)域,但是這部分內(nèi)存也被頻繁地使用竹握,而且也可能導(dǎo)致OutOfMemoryError 異常出現(xiàn)画株。
- 在 JDK 1.4 中新加入了 NIO 類,引入了一種基于通道(Channel)與緩沖區(qū)(Buffer)的 I/O方式啦辐,它可以 使用 Native 函數(shù)庫直接分配堆外內(nèi)存谓传,然后通過一個存儲在 Java 堆里的 DirectByteBuffer 對象作為這塊內(nèi)存的引用進行操作。這樣能在一些場景中顯著提高性能芹关,因為避免了在Java 堆和 Native 堆中來回復(fù)制數(shù)據(jù)续挟。