《深刻理解JVM》讀書筆記

抽時間從新讀了一遍《深刻理解JVM》一書。如下爲摘錄內容。java

1 java內存區域

clipboard.png

java虛擬機運行時數據區程序員

1.1 程序計數器

是一塊較小的內存空間,能夠看作是當前線程所執行的字節碼的行號指示器。每條線程都有一個獨立的程序計數器,各條線程之間計數器互不影響。算法

1.2 java虛擬機棧

描述的是java方法執行的內存模型:每一個方法在執行的同時都會建立一個棧幀用於存儲局部變量表、操做數棧、動態連接、方法出口等信息。安全

局部變量表存放了編譯器可知的各類基本數據類型、對象引用和returnAddress類型。數據結構

1.3 本地方法棧

虛擬機棧爲虛擬機執行java方法服務,二本地方法棧爲虛擬機使用到的Native方法服務。多線程

1.4 java堆

被全部線程共享的一塊內存區域,在虛擬機啓動時建立。java堆是垃圾收集器管理的主要區域,所以不少時候也被叫作GC堆。併發

1.5 方法區

各個線程共享的內存區域,用於存儲已被虛擬機加載的類信息、常量、靜態變量、即時編譯器編譯後的代碼等數據。函數

1.6 運行時常量池

方法區的一部分。須要注意的是string的intern方法在jdk1.6先後的不一樣。jdk1.6以後常量池放到了堆中。spa

1.7 直接內存

並非虛擬機運行時數據區的一部分,也不是java虛擬機規範中國定義的內存區域。NIO引入的通道和緩衝區可使用native函數庫直接分配對外內存。線程

2 垃圾收集器與內存分配策略

2.1 判斷對象是否存活的算法:

引用計數算法:很難解決對象之間相互循環引用的問題

可達性分析算法:經過一系列GC Roots的對象做爲起始點,從這些節點開始向下搜索,搜索所走過的路線稱爲引用鏈,當一個對象到GC Roots沒有任何引用鏈相連時,則證實此對象是不可用的。

2.2 垃圾收集算法

標記-清除算法:效率低,空間碎片化

複製算法:運行簡單高效,代價高,下降了一半的使用率

標記-整理算法

分代收集:新生代用複製算法,老年代用標記整理算法

3 虛擬機類加載機制

加載、驗證、準備、解析、初始化。

3.1 有且只有5種狀況必須當即對類進行初始化

1)遇到new、getstatic、putstatic或invokestatic這4條指令字節碼時,若是類沒有進行過初始化,則須要先觸發其初始化。

2)使用java.lang.reflect包的方法對類進行反射調用的時候,若是類沒有進行過初始化,則須要先觸發其初始化。

3)當初始化一個類的時候,若是發現其父類尚未進行過初始化,須要先觸發其父類的初始化。

4)當虛擬機啓動時,須要制定main,虛擬機會先初始化main類。

5)當使用jdk1.7的動態語言支持時,若是java.lang.invoke.MethodHandle實例最後的解析結果REF_getStatic、REF_putStatic、REF_invokeStatic的方法句柄,而且這個方法句柄所對應的類沒有進行過初始化,則須要先觸發其初始化。

3.2 類加載的過程

3.2.1 加載

1)經過一個類的全限定名來獲取定義此類的二進制字節流

2)將這個字節流所表明的靜態存儲結構轉換爲方法區的運行時數據結構

3)在內存中生成一個表明這個類的java.lang.Class對象,做爲方法區這個類的各類數據的訪問入口。

3.2.2 驗證

確保Class文件的字節流中包含的信息符合當前虛擬機的要求,而且不會危害虛擬機自身的安全。

文件格式驗證——元數據驗證——字節碼驗證——符號引用驗證

3.2.3 準備

正式爲類變量分配內存並設置類變量初始值的階段,這些變量所使用的內存都將在方法區中進行分配。這時候進行內存分配的僅包括類變量(被static修飾的變量),二不包括實例變量。

3.2.4 解析

解析階段是虛擬機將常量池內的符號引用替換爲直接引用的過程。

類和接口的解析、字段解析、類方法解析、接口方法解析

3.2.5 初始化

類初始化階段是類加載過程的最後一步。在準備階段,變量已經賦過一次系統要求的初始值,而在初始化階段,則根據程序員經過程序指定的主觀計劃去初始化類變量和其餘資源,或者能夠從另外一個角度來表達:初始化階段是執行類構造器<clinit>()方法的過程。

4 java內存模型

硬件的效率與一致性

clipboard.png

java內存模型(JMM)

clipboard.png

線程、主內存、工做內存之間的交互關係
java內存模型規定了全部的變量都存儲在主內存中,每條線程有本身的工做內存,線程的工做內存中保存了被該線程使用到的變量的主內存副本拷貝,線程對變量的全部操做(讀取、賦值)都必須在工做內存中進行,而不能直接讀寫主內存中的變量。線程間變量值的傳遞均須要經過主內存來完成。

java內存模型時圍繞着在併發過程當中如何處理原子性、可見性和有序性這三個特徵來創建的。

  • 原子性:經過read、load、assign、user、store、write操做來保證。經過lock和unlock也能夠知足。
  • 可見性:可見性是指當一個線程修改了共享變量的值,其餘線程可以當即得知這個修改。Java內存模型是經過在變量修改後將新值同步回主內存,在變量讀取前從主內存刷新變量值這種依賴主內存做爲傳遞媒介的方式來實現可見性的,不管普通變量仍是volatile變量都是如此,普通變量與volatile變量的區別是,volatile的特殊規則保證了新值可以當即同步到主內存,以及每次使用前當即從主內存刷新。volatile保證了多線程操做時變量的可見性,二普通變量不能保證這一點。(synchronized和final關鍵字)
  • 有序性:volatile和synchronized保證線程之間操做的有序性,volatile自己就包含了禁止指令重排序的語義。

先行發生原則 保證了咱們大多數狀況下不用關心太多。

相關文章
相關標籤/搜索