Java虛擬機常見面試題

一、java引用的四種狀態

強引用、軟引用、弱引用、虛引用。java

強引用

new一個Object存放在堆內存,而後用一個引用指向它,這個就是強引用。面試

若是一個對象具備強引用,那垃圾回收器不會回收它。當內存空間不足,java虛擬機寧願拋出outOfMemoryError錯誤,使程序異常終止,也不會隨意回收具備強引用的對象來解決內存不足的問題。算法

軟引用

若是一個對象只具備軟引用,則內存空間足夠時,垃圾回收器就不會回收它,若是內存空間不足了,就會回收這些對象的內存。數組

只要垃圾回收器沒有回收它,該對象就能夠被程序使用。弱引用可用來實現內存敏感的高速緩存。緩存

弱引用

只具備弱引用的對象擁有更短暫的生命週期。jvm

每次執行GC的時候,一旦發現了只具備弱引用的對象,無論當前內存空間足夠與否,都會回收它的內存。不過,因爲垃圾回收器是一個優先級很低的線程,所以不必定會很快發現那些只具備弱引用的對象。函數

虛引用

"虛引用",形同虛設,與其餘幾種引用不一樣,虛引用並不會決定對象的生命週期,若是一個對象僅持有虛引用,那麼它就和沒有任何引用同樣,在任什麼時候候均可能被垃圾回收器回收。.net

虛引用主要用來跟蹤對象被垃圾回收器的活動。線程

二、java中的內存劃分

2.1 程序計數器

內存空間小,線程私有。字節碼解釋器工做是就是經過改變這個計數器的值來選取下一條須要執行指令的字節碼指令,分支、循環、跳轉、異常處理、線程恢復等基礎功能都須要依賴計數器完成3d

若是線程正在執行一個 Java 方法,這個計數器記錄的是正在執行的虛擬機字節碼指令的地址;若是正在執行的是 Native 方法,這個計數器的值則爲 (Undefined)。此內存區域是惟一一個在 Java 虛擬機規範中沒有規定任何 OutOfMemoryError 狀況的區域。

2.2 虛擬機棧

線程私有,生命週期和線程一致。描述的是 Java 方法執行的內存模型:每一個方法在執行時都會牀建立一個棧幀(Stack Frame)用於存儲局部變量表、操做數棧、動態連接、方法出口等信息。每個方法從調用直至執行結束,就對應着一個棧幀從虛擬機棧中入棧到出棧的過程。

局部變量表:存放了編譯期可知的各類基本類型(boolean、byte、char、short、int、float、long、double)、對象引用(reference 類型)和 returnAddress 類型(指向了一條字節碼指令的地址)

StackOverflowError:線程請求的棧深度大於虛擬機所容許的深度。 OutOfMemoryError:若是虛擬機棧能夠動態擴展,而擴展時沒法申請到足夠的內存。

2.3 本地方法棧

區別於 Java 虛擬機棧的是,Java 虛擬機棧爲虛擬機執行 Java 方法(也就是字節碼)服務,而本地方法棧則爲虛擬機使用到的 Native 方法服務。也會有 StackOverflowError 和 OutOfMemoryError 異常。

2.4 堆

對於絕大多數應用來講,這塊區域是 JVM 所管理的內存中最大的一塊。線程共享,主要是存放對象實例和數組。內部會劃分出多個線程私有的分配緩衝區(Thread Local Allocation Buffer, TLAB)。能夠位於物理上不連續的空間,可是邏輯上要連續。

OutOfMemoryError:若是堆中沒有內存完成實例分配,而且堆也沒法再擴展時,拋出該異常。

2.5 方法區

屬於共享內存區域,存儲已被虛擬機加載的類信息、常量、靜態變量、即時編譯器編譯後的代碼等數據。

2.6 運行時常量池

屬於方法區的一部分。

屬於方法區一部分,用於存放編譯期生成的各類字面量和符號引用。編譯器和運行期(String 的 intern() )均可以將常量放入池中。內存有限,沒法申請時拋出 OutOfMemoryError。

2.7 直接內存

非虛擬機運行時數據區的部分

在 JDK 1.4 中新加入 NIO (New Input/Output) 類,引入了一種基於通道(Channel)和緩存(Buffer)的 I/O 方式,它可使用 Native 函數庫直接分配堆外內存,而後經過一個存儲在 Java 堆中的 DirectByteBuffer 對象做爲這塊內存的引用進行操做。能夠避免在 Java 堆和 Native 堆中來回的數據耗時操做。 OutOfMemoryError:會受到本機內存限制,若是內存區域總和大於物理內存限制從而致使動態擴展時出現該異常。

三、java對象在內存中的狀態

3.1 可達的/可觸及的

從根節點掃描,只要這個對象在引用鏈,就是可達的。

3.2 可恢復的

java對象再也不被任何變量引用就進入了可恢復狀態。

在回收該對象以前,該對象的finalize()方法進行資源清理。若是在finalize()方法中從新讓變量引用該對象,則對象再次變爲可達狀態,不然改狀態進入不可達狀態。

3.3 不可達的

java對象不被任何變量引用,且系統在調用對象finalize()方法後,依然沒有使該對象變成可達狀態,則該對象變成不可達狀態。

當java對象處於不可達狀態時,系統纔會真正回收該對象所佔有的資源。

4.判斷對象死亡的兩種經常使用算法

4.1 引用計數算法

4.2 根搜索算法

5.垃圾回收算法

5.1 標記-清除算法

算法分爲標記和清除兩個階段:首先標記出全部須要回收的對象,在標記完成後統一回收全部被標記的對象。

不足:一個是效率問題,標記和清除兩個過程的效率都不高,另外一個是空間問題,標記清除以後會產生大量不連續的內存碎片,空間碎片太多可能會致使之後再程序運行過程當中須要分配較大的對象時,沒法找到足夠的連續內存而不得不提早觸發另外一次垃圾收集動做。 清除不是擦除,內容不會被立刻清空,直到有新的的內容寫入纔會覆蓋。

5.2 複製算法

它將可用內存按照容量劃分爲大小相等的兩塊,每次只使用其中的一塊。當這塊的內存用完了,就將還活着的對象複製到另外一塊上面,而後再把已使用過的內存空間一次清理掉。這樣使得每次都是對整個半區進行內存回收,內存分配時也就不用考慮內存碎片等複雜狀況,只要移動堆頂指針,按順序分配內存便可。

不足:內存浪費。

實際中咱們並不須要按照1:1比例來劃份內存空間,如堆內存的新生代,將內存分爲一塊較大的Eden空間和兩塊較小的Survivor空間,每次使用Eden和其中一塊Survivor,當另外一個Survivor空間沒有足夠空間存放上一次新生代收集下來的存活對象時,這些對象將直接經過分配擔保機制進入老年代。

5.3 標記-整理算法

讓全部存活的對象都向一端移動,而後直接清理掉端邊界之外的內存。 主要用在老年代中

5.4 分代收集算法

存活率低:青年代採用複製算法。 存活率高:標記清理/標記整理算法

6.垃圾收集器

6.1 Serial收集器

6.2 ParNew 收集器

6.3 ParNew Scanvenge 收集器

6.4 CMS收集器

6.5 G1 收集器

7.java堆內存劃分

7.1 青年代

7.2 老年代

8.類加載機制

9.初始化順序

10.JVM參數

10.1 java對象分配與vm調優

引用

JVM常見面試題1

jvm常見面試題2

3

http://www.javashuo.com/article/p-uhqvzxiy-ms.html

相關文章
相關標籤/搜索