1. 程式人生 > >《深入理解java虛擬機器》第二章筆記

《深入理解java虛擬機器》第二章筆記

1. 執行時資料區域

名稱 是否共享 作用 存在的異常
程式計數器 執行緒私有 如果執行的是java方法,這個計數器記錄的是正在執行的虛擬機器位元組碼指令的地址
java虛擬機器棧 執行緒私有 每個方法在執行的同時會建立一個棧幀(區域性變量表,運算元棧等),方法的呼叫過程,對應一個棧幀在虛擬機器棧中的出入棧 StackOverflowError,OutofMemoryError
本地方法棧 執行緒私有 作用與虛擬機器棧類似,但是它是為Native方法服務的 StackOverflowError,OutofMemoryError
java堆 執行緒共享 所有的物件例項以及陣列都要在堆上分配,隨著技術的發展,現在變得不是那麼絕對了,垃圾回收比較多 OutofMemoryError
方法區 執行緒共享 用於儲存已被虛擬機器載入的類資訊,常量,靜態變數等。垃圾回收在此比較少 OutofMemoryError
執行時常量池 執行緒共享 屬於方法區,用於存放編譯期生成的 各種字面量和符號引用 OutofMemoryError

2. 物件探究

2.1 物件的建立

  1. 類載入檢查:

    • 遇到new指令時,檢查這個指令的引數是否能在常量池中定位到一個類的符號引用。
    • 檢查這個符號引用代表的類是否已被載入,解析和初始化過.

      1. 分配記憶體:等同於把一塊確定大小的記憶體從java堆中劃分出來
    • 指標碰撞:假設java堆中的記憶體是絕對規整的,所有用過的記憶體放在一邊,空閒的記憶體放在另一邊,那麼就可以用一個指標向空閒空間挪動一段與物件大小相等的距離。
    • 空閒列表:假設記憶體是不規整的,那虛擬機器就會維護一個列表,記錄哪些記憶體塊是可用的,然後去找一塊足夠大的劃分給物件例項,並更新列表記錄。

    ps:還要考慮併發問題,有兩種解決方案

    1. CAS來保證更新操作原子性
    2. 把記憶體分配按照執行緒劃分到不同的空間之中,也就是給每一個執行緒預先分配TLAB(本地執行緒分配快取),只有TLAB用完,才會同步鎖定

    3. 初始化為零值

    4. 進行必要設定

    比如這個物件是哪個類的例項,物件的雜湊碼等,還有是否啟用偏向鎖等,主要是對物件頭進行設定

2.2物件的記憶體佈局

2.2.1 物件頭

  1. 第一部分用於儲存物件自身的執行時資料

    如雜湊碼,GC分代年齡,鎖狀態標識等

  2. 第二部分是型別指標

    用來確定這個物件是哪個類的例項,如果物件是陣列的話,還得有一塊用於記錄陣列長度的資料。

2.2.2 例項資料

  • 儲存的是有效資訊,也就是所定義的各種型別的欄位內容。
  • 這部分的儲存順序會受 虛擬機器分配策略引數,欄位在Java原始碼中的定義順序的影響

2.2.3 對齊填充

這部分沒什麼含義的,主要起著佔位符的作用,比如物件的大小必須是8位元組的整數倍,當物件例項資料部分沒有對齊時,就要通過它來填充

2.3物件的訪問定位

主流的訪問方式有 使用控制代碼 和直接指標 這兩種
1. 使用控制代碼
- java 堆劃分出一塊記憶體空間來作為控制代碼池,reference中存的就是物件的 控制代碼地址
這裡寫圖片描述

最大的好處是reference中儲存的是穩定的控制代碼地址,在物件被移動時只會改控制代碼中的例項資料指標,而reference本身不需要修改

2. 直接指標
reference中存的就是物件地址
image
最大的好處是速度更快,節省了一次指標定位的時間開銷。

本書討論的虛擬機器是sun hotspot,它用的是直接指標方式