大廠面試必備(三)——JVM(Java虛擬機)

p#### 一、運行時數據區-幀棧詳解
在這裏插入圖片描述
    完整的Java虛擬機是由三部分組成的:類裝載子系統、運行時數據區(內存模型)、字節碼執行引擎。其中運行時數據區包含了堆、棧(線程)、本地方法棧、方法區(元空間)、程序計數器。
    堆:堆是Java對象的存儲區域,任何用new字段分配的Java對象實例和數組,都被分配在堆上,Java堆可使用-Xms -Xmx進行內存控制,值得一提的是從JDK1.7版本之後,運行時常量池從方法區移到了堆上。
    方法區:它用於存儲已被虛擬機加載的類信息,常量,靜態變量,即時編譯器編譯後的代碼等數據,方法區在JDK1.7版本及以前被稱爲永久代,從JDK1.8永久代被移除。
    虛擬機棧:虛擬機棧中執行每個方法的時候,都會創建一個棧幀用於存儲局部變量表,操作數棧,動態鏈接,方法出口等信息。
    本地方法棧:與虛擬機棧發揮的作用相似,相比於虛擬機棧爲Java方法服務,本地方法棧爲虛擬機使用的Native方法服務,執行每個本地方法的時候,都會創建一個棧幀用於存儲局部變量表,操作數棧,動態鏈接,方法出口等信息。
    程序計數器:指示Java虛擬機下一條需要執行的字節碼指令。
    棧的主要作用是放各個線程的局部變量。那麼棧是如何存放這些局部變量的,這就涉及到另一個詞——棧幀。比如一個類有多個方法,當一個線程執行到一個方法的時候,虛擬機會馬上給這個方法分配一個獨立的一塊內存區域(即棧幀),一個方法對應一塊棧幀內存區域。
在這裏插入圖片描述
    這裏的棧也就是我們平時所說的數據結構的棧,符合先進後出的原則。如圖,當線程執行main方法的時候,棧會分配一個棧幀存放main方法的局部變量。當main方法調用compute方法時,棧會分配一個棧幀存放compute方法的局部變量並且進棧。當compute方法執行結束後,存放compute方法局部變量的棧幀就會被銷燬(出棧);接着mian方法會繼續往後執行,當main方法執行結束後,main方法的棧幀才被銷燬(出棧)。符合先進後出的規律。

二、堆

1、可達性分析算法

    將“GC Roots”對象作爲起點,從這些節點開始向下搜索引用的對象,找到的對象都標記爲非垃圾對象,其餘未標記的對象都是垃圾對象。
    GC Roots根節點:線程棧的本地變量、靜態變量、本地方法棧的變量等等。
在這裏插入圖片描述

2、垃圾回收機制在這裏插入圖片描述

    當對象剛創建的時候,會存放在Eden區;當Eden區內存空間不足的時候,會進行一次垃圾回收,即minor gc;有被引用的對象會通過複製算法移動到此時的From區,並且這些對象上的一個叫“分代年齡”的變量會加1,而不在引用鏈上的對象就會被回收。當進行第二次minor gc時,Eden區和From區上的有被引用的對象會通過複製算法被移動到To區,並且對象的“分代年齡”變量加1,沒有被引用的對象被回收;此時,To區變成From區,From區變成To區;如此往復,當對象的“分代年齡”變量值爲15時,該對象會被複制移動到老年代。(默認分代年齡15時會移動到老年代,但是這個值我們是可以修改的)
    那是不是老年代的對象就永遠存在,不會被回收呢?其實,老年代的內存大小也是有限的,當老年代空間不足的時候,會進行一次full GC,對整個堆區域進行垃圾回收,如果回收過後還是空間不足,那麼此時就會出現——內存溢出異常(java.lang.OutOfMemoryError)。
    每進行一次full GC的時候,線程都會被停止,出現STW(stop the word)現象(雖然minor gc也會STW,但是時間很短,用戶幾乎感知不到)。如果經常出現STW,用戶體驗是非常不好的,所以需要通過虛擬機調優來減少STW的出現。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章