1. 程式人生 > 資訊 >Meta(Facebook)被調查評為“2021 年度最差公司”,微軟獲評最佳

Meta(Facebook)被調查評為“2021 年度最差公司”,微軟獲評最佳

參考《深入理解java虛擬機器:JVM高階特性與最佳實踐(第三版)》
參考https://www.cnblogs.com/noteless/p/9510252.html

jvm執行時資料區域

JVM在執行java程式過程中會將其管理的記憶體劃分為若干個不同的資料區域,如下圖所示:

各區丟擲異常情況

程式計數器

可以看作是當前執行緒做執行的位元組碼的行號指示器。在JVM概念模型裡,位元組碼直譯器工作時就是通過改變這個計數器的值來選取下一條需要執行的位元組碼指令,他是程式控制流的指示器。程式計數器是執行緒私有的,可以用於上下文切換。如果執行緒正在執行一個java方法,這個計數器記錄的是正在執行的JVM位元組碼指令的地址;如果正在執行native方法,計數器為空。此記憶體區域是唯一一個在《JVM規範》中沒有規定任何outOfMemoryError情況的區域。

虛擬機器棧

虛擬機器棧是執行緒私有的,生命週期和執行緒相同。虛擬機器棧描述的是java方法執行的執行緒記憶體模型:每個方法執行時,jvm會同步建立一個棧幀用於儲存區域性變量表,運算元棧,動態連結,方法出口等資訊。每個方法被呼叫直到執行完畢的過程對應著一個棧幀在虛擬機器棧中從入棧到出棧的過程。
區域性變量表存放了編譯器可知的各種基本資料型別(int,long等)、物件引用和returnAddress型別。這寫資料型別在區域性變量表中的儲存空間以區域性變數槽表示,其中long\double佔用兩個槽,其他資料型別佔用一個槽。區域性變量表所需的空間在編譯期間完成分配,不同虛擬機器的變數槽的記憶體空間可能不一樣(一個變數32位元或者64位元)。
如果執行緒請求的棧深度超過了虛擬機器允許的深度時會丟擲StackOverflowError異常;如果jvm棧容量可以動態擴充套件,當棧擴充套件時無法申請到足夠的記憶體會丟擲OutOfMemoryError異常(HopSpot不允許棧空間擴充套件,只有在申請的時候空間不足會丟擲該異常,在執行的時候不會出現該異常)。

本地方法棧

和虛擬機器棧類似,只不過本地方法棧服務於本地方法(native方法)。也會丟擲StackOverflowError異常和OutOfMemoryError異常。

java堆

java堆是虛擬機器所管理記憶體中最大的一塊,被所有執行緒共享,唯一作用是存放物件,幾乎所有的物件例項及陣列都分配在java堆上。基於經典分代GC設計的JVM中一般將java堆分成新生代、老年代、永久代。不過當前也出現了不採用分代GC的收集器。
java堆可以處於不連續的記憶體空間上,但是出於實現簡單、儲存高效的考慮,一般對於大物件要求記憶體連續。
可以通過-Xmx -Xms設定堆大小,當堆記憶體超過上限時會丟擲OutOfMemoryError異常。

方法區

方法區被各個執行緒共享,用於儲存已被虛擬機器載入的型別資訊、常量、靜態變數、即時編譯器編譯後的程式碼快取等資料。
jdk8以前,Hotspot設計團隊把收集器的分代設計擴充套件至方法區或者說用永久代實現了方法區,所以有的人會認為方法區是永久代,實際上是不嚴謹的。jdk8將方法區採用本地記憶體來實現,這個空間叫做元空間(meta-space),方法區無法滿足新的記憶體分配需求時,將丟擲OutOfMemoryError異常。

執行時常量池

Class檔案中除了有類版本、欄位、方法、介面等資訊的描述外,還有一項資訊是常量池表,用於存放編譯期間生成的各種字面量和符號引用,常量池表在類載入後存放到方法區的執行時常量池中。執行時常量池一般除了儲存class檔案中描述的符號引用外,還會把符號引用翻譯出來的直接引用也儲存在執行時常量池中。
另外執行時常量池具備動態性,處理類載入時匯入的常量外,可以在程式執行中加入新的常量。常量池無法再申請記憶體的時候會丟擲OutOfMemoryError異常。

直接記憶體

直接記憶體不是JVM執行時資料區的一部分,也不是《規範》中定義的記憶體區域,但是這部分可能被頻繁使用,而且也會導致OutOfMemoryError異常。