微吼云上線多路互動直播服務 加速多場景互動直播落地
862
2025-04-02
JVM
PS:JVM部分參考了《深入理解Java虛擬機 - 第二版》(周志明). 個人認為《深入理解Java虛擬機 - 第二版》上的部分內容已經過時 有些知識請各位同學明鑒,此外我后續會根據 《深入理解Java虛擬機 - 第三版》的內容來做更新和修改。
JVM運行時內存分區
以HotSpot為例:
JDK8之前:
線程私有的部分有:程序計數器(PC寄存器),JAVA虛擬機棧,本地方法棧(native)。
線程共享部分有: GC堆,永久代(是方法區的一種實現)。
JDK8之后:
線程私有的部分不變, 線程共享部分的永久代改為了元空間(MetaSpace) (永久代和元空間都是方法區的實現),字符串常量池也移動到了heap空間
程序計數器是一塊較小的內存空間,它的作用是作為當前線程執行的字節碼的行號計數器。 當字節碼解釋器工作時,通過改變行號計數器的值來選取下一條要執行的字節碼指令。?分支,循環,跳轉,異常處理,線程恢復等功能都需要依賴程序計數器完成。
程序計數器是屬于線程私有的部分。 當cpu在多個線程之間切換執行時,需要記錄下當前線程執行的字節碼的位置, 以便下次切換回當前線程時,能夠繼續執行字節碼指令, 所以每個線程都需要有自己的程序計數器。
如果當前線程執行的是java方法,那么程序計數器記錄的是字節碼指令的地址。
如果當前線程執行的native方法,那么程序計數器記錄的值為空(undefined)。
程序計數器這部分內存區域是JVM中唯一不會出現OOM錯誤的區域
程序計數器的生命周期與線程相同,即程序計數器隨著線程創建而創建, 隨著線程的銷毀而銷毀。
使用 javap -c 反編譯class文件后的代碼如下, 紅框里的就是字節碼的偏移地址:
Java虛擬機棧與程序計數器一樣,都是線程私有的部分,生命周期也跟線程一樣。
Java虛擬機棧描述的是Java方法運行時的內存模型,它由一個一個的棧幀組成。
棧幀是用于支持Java方法運行時的數據結構。 棧幀包含了局部變量表,操作數棧,動態連接,方法出口等信息。 每個方法執行時,都會在java虛擬機棧中創建一個棧幀。 對方法的調用和返回,就對應著棧幀的入棧和出棧的過程。
Java虛擬機棧:
局部變量表用于存儲方法參數和方法內定義的局部變量。 局部變量表存放了各種已知的數據類型的變量。?一個局部變量的類型可以是基本數據類型 (int,short,float,double,boolean,long,byte,char)或引用類型(reference)。 在Java代碼被編譯成class字節碼后,方法Code屬性的locals就確定了方法的局部變量表的大小。 局部變量表以slot為最小單位,一個slot代表4個字節,也就是32位長度的大小。
操作數棧是一個后進先出(LIFO)的數據結構。?它存儲的是方法在進行數據運算時的元素。?和局部變量表一樣,操作數棧的每個元素的類型也可以是基本數據類型和引用類型。 操作數棧的深度不會超過 Code屬性的stack值。
使用javap -c 反編譯class文件后可以得到的字節碼指令如下:
了解動態連接首先需要了解符號引用和直接引用
符號引用: 符號引用存于Class文件常量池。分為類的全限定名,方法名和描述符,字段名和描述符。
直接引用: 指向目標的指針,可以簡單理解為目標的內存地址(如指向類的字段的內存地址)。
Class文件常量池如下(javap -c 反編譯class文件后的字節碼):
在虛擬機棧中,每個棧幀都包含了一個該棧幀所屬方法的符號引用, 持有這個符號引用的目的是為了支持方法調用過程中的動態連接。 這些符號引用有的一部分會在JVM類解析階段就會轉為直接引用,這部分轉換成為靜態解析。 還有一部分會在運行時轉為直接引用,這部分稱為動態連接。
當方法執行時,有2種方式可以退出該方法。
正常退出: 當方法執行時,執行到return指令,該方法就會正常退出。 一般來說,方法正常退出時,調用線程的程序計數器的值可以作為方法返回的地址, 棧幀中可能會保存這個計數器的值。
異常退出: 在方法執行過程中遇到了異常,并且方法內部沒有處理這個異常,就會導致方法退出。 方法異常退出時,返回地址需要通過異常處理器表來確定的,棧幀中不會保存這部分值。
無論何種退出方式,在方法退出后,都需要回到方法被調用的位置,程序才能繼續執行。
本地方法棧與虛擬機棧的作用是相似的, 不過虛擬機棧是為執行Java方法提供服務的, 本地方法棧視為執行native方法提供服務的。?在本地方法執行的時候,也會在本地方法棧中創建棧幀, 用于存放該本地方法的局部變量表,操作數棧,動態連接和方法返回地址等信息。
堆是JVM中內存占用最大的一塊區域,它是所有線程共享的一塊區域。 堆的作用是為對象分配內存并存儲和回收它們。 堆是垃圾回收的主要區域,所以堆區也被成為GC堆。
堆區可以劃分為?新生代(Young Generation),老年代(Old Generation)?和 永久代(Permanent Generation),但永久代已被元空間代替,?元空間存儲的是類的元信息,幾乎不可能發生GC。
新生代再細分可以分為:?Eden空間,From Survivor空間和To Survivor空間。
缺省狀態下新生代占堆區的 1/3,老年代占堆區的2/3, eden空間占新生代的80%,2個Survivor空間棧新生代的20%, FromSurvivor和ToSurvivor的空間占比為1:1。
(通過-XX:NewRatio參數可以調整新生代和老年代的空間占比) (通過-XX:SurvivorRatio參數可以調整eden和survivor的空間占比)
發生在新生代的GC叫做Young GC或Minor GC, 發生在老年代的GC叫做Old GC或Major GC
堆:
PS: FromSurvivor和ToSurvivor這兩塊內存空間并不是固定的, 在進行GC的時候,這兩塊內存會輪流替換使用。這部分內容參考GC部分。
PS: 有的文章說 Full GC與Major GC一樣是屬于對老年代的GC, 也有的文章說 Full GC 是對整個堆區的GC,所以這點需要各位同學自行分辨Full GC語義。 見:?知乎討論
方法區在JVM規范里也是各個線程共享的一部分區域, 它用于存儲已被jvm加載的類的元信息,運行時常量池等數據。
HotSpot虛擬機對于方法區的實現在jdk8之前為永久代,在jdk8之后, HotSpot移除了永久代,新增了元空間。
元空間使用的是本地內存,所以元空間僅受本地物理內存的限制。 元空間存儲著已被加載的類的方法描述,字段描述,運行時常量池等信息。
字符串常量池在jdk7已經從永久代轉移到了堆內存之中。
無論是永久代還是元空間,都有可能發生OOM。
JavaVirtualMachineError
當前線程執行或請求的棧的大小超過了Java 虛擬機棧的最大空間(比如遞歸嵌套調用太深),就可能出現StackOverflowError錯誤
發生OOM的情況:
java heap space
當需要為對象分配內存時,堆空間占用已經達到最大值, 無法繼續為對象分配內存,可能會出現OOM: java heap space錯誤。
Requested array size exceeds VM limit
當為數組分配內存時,數組需要的容量超過了虛擬機的限制范圍, 就會拋出OOM: Requested array size exceeds VM limit。
根據我的測試(jdk11/jdk14),Integer.MAX_VALUE - 2 是虛擬機能為數組分配的最大容量,當數組長度為 Integer.MAX_VALUE - 1 時就會拋出 OOM:Requested array size exceeds VM limit
GC overhead limit exceed
垃圾回收器花費了很長時間GC,但是GC回收的內存非常少, 就可能拋出OOM:GC overhead limit exceed 錯誤。
但是這點在我的機器上測試不出來,可能與jdk版本或gc收集器或Xmx分配內存的大小有關, 一直拋出的是java heap space
Direct buffer memory
當程序分配了超額的本地物理內存(native memory/ direct buffer), minor gc(young gc)并不會回收這部分內存, 只有 full gc才會回收直接內存,如果不發生full gc, 但直接內存卻被使用完了,那么可能會發生 OOM: Direct buffer memory。
unable to create new native thread
操作系統的線程資源是有限的, 如果程序創建的線程資源太多(無需超過平臺限制的線程資源上限), 就可能發生 OOM: unable to create new native thread 錯誤。
Metaspace
當加載到元空間中的類的信息太多,就有可能導致 OOM : Metaspace。
使用cglib的庫,可以動態生成class,所以可以使用cglib測試此錯誤。
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。