JVM運行時數據區學習筆記

1 程序計數器
  1. 很小的一塊內存區域,可以看做是當前線程執行的字節碼的行號指示器,字節碼解釋器工作時就是通過改變這個計數器的值來選取下一條需要執行的字節碼指令
  2. 分支、循環、跳轉、異常處理、線程恢復等基礎功能都是依賴程序計數器來完成的。所以程序計數器記錄的是當前執行的字節碼指令地址,當執行完成之後再跳轉到下一行,畢竟比如說分支執行完成之前是不知道下一條應該是哪一行的。
  3. 因爲多線程切換後要恢復到正確的執行位置,所以每條線程都需要有一個獨立的行號計數器
  4. 程序計數器也是虛擬機規範中唯一沒有指明OutOfMemoryError的區域
2 Java虛擬機棧
  1. 主要描述的是Java方法執行的內存模型,每個方法執行時都會創建一個棧幀,用於儲存局部變量表、操作數棧、動態練級誒、方法的返回地址、還有一些其他信息(可以沒有)。每個方法的的調用和返回,都對應着一個棧幀的入棧和出棧
  2. 局部變量表存放了編譯期可知的各種基本數據類型(8種)以及對象引用類型和returnAddress類型(指向了一條字節碼指令的地址)
  3. 比較特殊的是double和long類型的數據會佔據兩個slot空間,其餘所有都只會佔用一個空間,局部變量表的內存空間是在編譯期完成分配的,所有棧幀中的局部變量空間是完全確定的
  4. 可能會出現兩種異常,若線程請求深度大於虛擬機棧所運行的最大深度,會拋出StackOverflowError異常。若虛擬機棧在擴展時無法申請到足夠的空間,會拋出OutOfMemoryError異常
  5. 操作數棧的內存空間也是確定的,記錄方法中的計算時入棧和出棧的操作
3 本地方法棧

與Java虛擬機棧相對應,Java虛擬機棧是執行Java方法的,而本地方法棧是執行native方法的,也同樣存在兩種異常情況

!!!以上程序計數器、Java虛擬機棧、本地方法棧都是線程私有的,每一個線程都對應有這三個區域,並且沒有垃圾回收

4 Java堆
  1. 是Java虛擬機管理內存中最大的一塊內存區域,默認起始內存爲1/64的物理電腦內存,最大內存爲1/4。所有對象的實例以及數組都要在堆上分配(目前是比較絕對的,但是隨着虛擬機技術的發展,棧上分配局部變量內存也許也是可以考慮的,可以有效減少垃圾回收)
  2. 從內存回收的角度,Java堆可以分爲新生代和老年代,比例大概默認爲1:2,新生代又可以分爲Eden空間、Form Survivor空間、To Survivor空間,大概比例默認爲8:1:1。絕大多數對象的分配都是在Eden空間的,然後隨着內存的回收會來到Form或者To區,這兩個空間不會同時儲存對象的,最後年齡大的對象會去到老年代中。若是大對象可以直接在老年代中分配。
  3. 從內存分配的角度來說,Java堆可以分出多個線程私有的分配緩衝區(TLAB),因爲線程併發的情況下,對於堆上內存分配是可能出現錯誤的,所以每次操作都需要加鎖,而削弱了性能。若每個線程都有部分自己私有的分配區域,先在這部分內存上分配便可以加快效率。
  4. 內存的進一步劃分的目的是爲了更好地回收內存,或者是爲了更快的分配內存
  5. Java堆是可以處於物理上不連續的內存空間,只需要邏輯上連續即可,若堆上沒有足夠的空間完成對象分配時,且無法再擴展時,會拋出OutOfMemoryError異常
5 方法區
  1. 儲存已被虛擬機加載的類信息、常亮、靜態變量、即時編譯器編譯後的代碼等數據,HotSpot虛擬機是用永久代去實現的方法區,但較容易出現內存溢出的問題。Java7中把字符串常量池移除到了堆空間,Java8中會用元空間代替永久代。
  2. 方法區是可以不實現垃圾收集的,但出現內存不足情況依然會拋出OutOfMemoryError異常的

主要內容都是來源於學習《深入理解Java虛擬機》所勾畫的筆記

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