- Java虛擬機運行時資料區
- 方法區:存盤 類資訊、常量、靜態變數、即使編譯器編譯后的代碼等資料,也有別名叫做非堆, 方法區其中有包含有 運行時常量池,用于存放編譯期生成的各種字面量和符號參考,其中,可通過String.intern()方法將字串放入運行時常量池中,
- 堆:存盤的是類實體物件,陣列, JVM 所管理的記憶體中最大的一塊,Java堆是被所有執行緒共享的一塊記憶體區域,在虛擬機啟動時創建, 從記憶體回收的角度來看,由于現在收集器基本都采用 分代收集演算法,所以堆可以細分為 新生代 和老年代;再細分 新生代可以分為:Eden空間,From Survivor空間和To Survivor空間等,
- 虛擬機堆疊:每個方法在執行的同時都會創建一個堆疊幀用于存盤區域變數表、運算元堆疊、動態鏈接、方法出口等資訊,每個方法從呼叫直至執行完成的程序,就對應著一個堆疊幀在虛擬機堆疊中入堆疊和出堆疊的程序,
- 本地方法堆疊: 本地方法堆疊服務于虛擬機執行Native方法服務,作用與虛擬機堆疊相似,
- 程式計數器:程式計數器是一塊較小的記憶體空間,它可以看作是當前執行緒所執行的位元組碼的行號指示器,位元組碼解釋器作業時就是通過改變這個計數器的值來選取下一條需要執行的位元組碼指令,分支、回圈、跳轉、例外處理、執行緒恢復等基礎功能都需要依賴這個計數器來完成,每條執行緒都需要有一個獨立的程式計數器
- Java類加載機制
- 裝載
- 加載方式:
- 從本地系統中直接加載
- 通過網路下載class檔案
- 從歸檔檔案中加載class檔案
- 從專有資料庫中提取class檔案
- 將Java源檔案 動態編譯為class檔案,也就是運行時計算而成
- 從加密檔案中獲取
- 加載方式:
- 連接
- 驗證
- 驗證java版本號,檔案格式, 元資料校驗(是否有父類,是否繼承了final類等java 語法) 位元組碼驗證(運行檢查,堆疊資料型別和操作碼操作引數是否吻合)
- 準備
- private static final int a =1; constantValue 通知虛擬機生成常量賦值,不需要開辟記憶體, 基于final static 修飾的 基本資料型別和String起作用
- 決議
- 將常量池內的符號參考轉變成直接參考
- 初始化
- 初始化什么時候被觸發? 類 主動使用到的時候 1 創建類的實體,也就是new 2 訪問某個類或者介面的靜態變數,給該靜態變數賦值 3 呼叫類的靜態方法 4.反射 (class.forname("...")) 5.初始化某個類的子類,則其父類也會被初始化 6.java 虛擬機啟動時被標明為啟動類的類(如springboot啟動類)
- 使用
- 卸載
- 1.該類所有的實體都已經被回收,即java堆中不存在該類的任何實體 2. 加載該類的classloader 已經被回收 3. 該類對應的java.lang.Class物件沒有任何地方被參考,無法在任何地方通過反射訪問該類的方法
- 裝載
- 類加載器
-
類加載器的加載特性:
- 全盤型別機制
- 父類委托
- 快取機制
加載完之后開始使用類,此時需要運行時資料區
- PC暫存器
- 本地方法堆疊
- 虛擬機堆疊
- 堆:裝載的時候,存盤所有class實體 空間不足拋出oom
- 方法區 :
- 執行緒共享區域,class結構資訊,運行時常量池,方法,構造器,方法資料,靜態定義
- 記憶體不夠時,拋出OOM
- 運行時常量池(在方法區中):包含字串常量池

- 動態鏈接: 符號參考變成直接參考會改變這個動態鏈接屬性
-
類加載器的加載特性:
- Java物件記憶體布局
- Java物件記憶體分為三部分: 物件頭,實體資料,對齊填充
- 物件頭
- Mark Word : 哈希碼,分代年齡,執行緒持有的鎖,偏向鎖ID,偏向時間戳,鎖狀態,還有1bit的占位符
- class Pointer: 指的是型別指標,物件指向它的類元資料的指標,虛擬機通過這個指標來確定這個物件是哪個類的實體
-
實體資料
- 物件真正存盤的有效資訊,代碼中所定義的各種型別的欄位內容,無論是從父類繼承下來的,還是在子類中定義的,都需要記錄起來,這部分的存盤順序會受到虛擬機分配策略引數和欄位在Java遠嗎中定義順序的影響,HotSpot虛擬機默認的分配策略為longs/doubles、ints、shorts/chars、bytes/booleans、oops,從分配策略中可以看出,先攻寬度的欄位總是被分配到一起的,在滿足這個前提條件的情況下,在父類中定義的變數會出現在子類之前,
- 對齊填充
- HotSpot VM 要求物件大小必須是8位元組的整數倍
- 物件頭
- 物件定位方式:
- 建立物件是為了使用物件,我們的Java程式需要通過堆疊上的reference資料來操作對上的具體物件,目前主流的訪問方式有兩種:使用句柄和直接指標兩種方式

-

使用句柄訪問的最大好處就是reference中存盤的是穩定的句柄地址,在物件被移動(垃圾回收)時,只會改變句柄中的實體資料指標,而reference本身不修改,
- 使用直接指標訪問方式的好處是速度更快,節省了中間轉發訪問的步驟,
- Java物件的生命周期
- 創建階段
- 應用階段
- 不可見階段
- 不可達階段
- 收集階段
- 終結階段
- 空間重分配階段

- 物件創建程序:

- 判斷物件是否已經“死”了的演算法有兩種:
- 參考計數演算法: 給物件中添加一個參考計數器,每當有一個地方參考它時,計數器值就加1;當參考失效時,計數器值就減1;任何時刻計數器為0的情況,都是不可能再被使用的,
- 參考計數演算法的缺陷就是它很難解決物件之間相互回圈參考的問題
- 可達性分析演算法:通過一系列的成為“GC Roots"的物件作為起始點,從這些節點開始向下搜索,搜索所走過的路徑成為參考鏈,當一個物件到GC roots沒有任何參考鏈相連時,則證明此物件是不可用的,
- 在Java中,可作為GC roots的物件包括下面幾種:
- 虛擬機堆疊(堆疊幀中的本地變數表)中參考的物件
- 方法區中類靜態屬性參考的物件
- 方法區中常量參考的物件
- 本地方法堆疊中JNI(即一般說的Native方法)參考的物件,
- 參考計數演算法: 給物件中添加一個參考計數器,每當有一個地方參考它時,計數器值就加1;當參考失效時,計數器值就減1;任何時刻計數器為0的情況,都是不可能再被使用的,
-
參考分類:
-
強參考:只要強參考還存在,垃圾收集器永遠不會回收掉被參考的物件
- 軟參考:對于軟參考關聯著的物件,在系統將要發生記憶體溢位例外之前,將會把這些物件列進回收范圍之中進行第二次回收
- 弱參考: 被弱參考關聯的物件只能生存到下一次GC發生之前,
- 虛參考: 為一個物件設定虛參考關聯的唯一目的就是能在這個物件被收集器回收時收到一個系統通知,
-
- 垃圾收集演算法
- 標記-清除演算法
- 不足:
- 效率問題:標記和清除兩個程序的效率不高
- 空間問題:標記清除后會產生大量不連續的記憶體碎片,碎片太多導致以后再程式運行程序中需要分配較大物件時,無法找到足夠的連續記憶體而不得不提前觸發另一次垃圾收集動作,
- 不足:
- 復制演算法:將可用的記憶體按容量劃分大小相等的涼快,每次只使用其中的一塊,當這一塊的記憶體用完了,就將還存活著的物件復制到另一塊上面,然后再把已使用過的記憶體空間一次清理掉,這樣使得每次都是對整個半區進行記憶體回收,記憶體分配時也就不用考慮記憶體碎片等復雜情況,只要移動堆頂指標,按順序分配記憶體即可,簡單高效,
- 不足:
- 當物件存活率較高時,要進行較多的復制操作,效率會降低,
- 不足:
- 標記-整理演算法:標記程序仍然與”標記-清除演算法一樣,后續讓所有存活的物件都向一端移動,然后直接清理掉端邊界以外的記憶體,
- 分代收集演算法:
- 這種演算法并沒有什么新的思想,只是根據物件存活周期的不同將記憶體劃分為幾塊,一般是把Java堆分為新生代和老年代,這樣就可以根據各個年代的特點采用最適合的收集演算法,在新生代中,每次垃圾收集時都發現有大批物件死去,只有少量存活,那就選用復制演算法,只需要付出少量存活物件的復制成本就可以完成,而老年代中因為物件存活率高、沒有額外空間對他進行分配擔保,就必須使用“標記-清理”或者“標記-整理”演算法來進行回收,
- 標記-清除演算法
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/245982.html
標籤:其他
上一篇:字串
