1. 程式人生 > >《深入理解JVM虛擬機器》讀書筆記(一)

《深入理解JVM虛擬機器》讀書筆記(一)

此書一共分為5個部分:

  1. 走近Java
  2. 自動記憶體管理機制
  3. 虛擬機器執行子系統
  4. 程式編譯與程式碼優化
  5. 高效併發

這裡,我直接跳過第一部分的內容,開始第二部分的內容。此部分包括:

  • Java記憶體區域與記憶體溢位異常
  • 垃圾收集器與記憶體分配策略
  • 虛擬機器效能監控與故障處理工具
  • 調優案例分析與實戰

開記!!!

首先引用原書中的一句話,“Java與C++之間有一堵由記憶體動態分配和垃圾收集技術所圍成的“高牆”, 牆外面的人想進去, 牆裡面的人卻想出來。

一. 執行時資料區域

Java虛擬機器在執行Java程式的過程中會把它所管理的記憶體劃分為若干個不同的資料區域。

程式計數器:一塊很小的記憶體區域,用來記錄程式下一條位元組碼指令的地址,如果執行緒正在執行的是一個Java方法,這個程式計數器記錄的是正在執行的虛擬機器位元組碼指令地址;如果正在執行的是一個Native方法,這個計數器的值則為空。

此區域是Java虛擬機器規範中沒有規定任何OutofMemoryError情況的區域。

虛擬機器棧:執行緒私有,生命週期與執行緒相同,這個區域描述的是Java方法執行的記憶體模型:每個方法在執行的時候都會建立一個棧幀(Stack Frame)用於儲存區域性變量表,運算元棧,動態連結,方法出口等資訊。
在虛擬機器規範中,這個區域規定了2種異常:一是執行緒請求的棧深度大於虛擬機器所允許的深度將丟擲StackOverflowError異常;如果虛擬機器棧可以動態擴充套件,如果申請到足夠的記憶體,就會丟擲OutOfMemoryError異常。


本地方法棧:與虛擬機器棧型別,只不過本地方法棧是呼叫本地的Native方法,與虛擬機器棧一樣會丟擲StackOverflowError及OutOfMemoryError異常。


Java堆:所有物件例項及陣列都要在堆上分配(Java虛擬機器規範描述),但是隨著JIT編譯器的發展與逃逸分析技術逐漸成熟,棧上分配,標量替換優化技術將會導致一些微妙的變化。
Java堆可以分為新生代和老年代;再細緻一點新生代分為Eden空間,From Survivors空間,To Survivors空間。進一步劃分是為了更好的回收記憶體,跟回收演算法有關係。
虛擬機器規範中規定,Java堆可以處於物理上不連續的記憶體空間中,只要邏輯上是連續的即可。會發生OutOfMemoryError異常。


方法區:跟Java堆一樣是執行緒共享的記憶體區域,它用於儲存已被虛擬機器載入的類資訊,常量,靜態變數,即時編譯器編譯後的程式碼等資料。虛擬機器規範把這個區域描述為堆的一個邏輯部分,但它有一個別名叫非堆(Non-Heap),會發生OutOfMemoryError異常。


執行時常量池:是方法區的一部分,用來儲存各種字面量及符號引用,這部分內容將在類載入後進入方法區的執行時常量池中存放。
常量池具有動態性,執行期間也可能將新的常量放入池中,這種特性用的比較多的是String的intern()方法。會發生OutOfMemoryError異常。


直接記憶體:並不是虛擬機器執行時資料區的一部分,也不是Java虛擬機器規範中定義的記憶體區域,但這部分也被頻繁的使用,最典型的應用便是JDK1.4新增的NIO通過DirectByteBuffer物件來操作這部分記憶體,這樣避免了Java堆跟Native堆中資料來回複製資料的開銷。


二. HotSpot虛擬機器物件探祕

Java物件的建立過程:只提供一個圖,細節太多。


Java物件的記憶體分佈:

三個區域--物件頭Header,例項資料Instance Data,對齊資料Padding

其中物件頭分為2個部分,分別是Mark word與型別指標(指向它的類元資料)