1. 程式人生 > >深入理解Java虛擬機器筆記(一)

深入理解Java虛擬機器筆記(一)

內容主要參考《深入理解Java虛擬機器(第2版)》

Java和C++之間有一堵由記憶體動態分配和垃圾收集技術所圍成的“高牆”,牆外面的人想進去,牆裡面的人想出來。

一 JVM執行時資料區

執行時資料區結構如下圖:


1 程式計數器:記憶體較小,執行緒執行的位元組碼的行號指示器,執行緒私有。唯一一個在Java虛擬機器規範中沒有規定任何OutOfMemoryError情況的區域。

2 Java虛擬機器棧:執行緒私有的,用於存貯區域性變量表、運算元棧、動態連結、方法出口等資訊。如果執行緒請求的棧深度大於虛擬機器所允許的深度,將丟擲StackOverflowError異常。

3 本地方法棧:和2相似,區別是虛擬機器棧為虛擬機器執行Java方法服務,而本地方法棧為虛擬機器使用到的Native方法服務。

4 Java堆:記憶體中最大的一塊,所有執行緒共享。作用是:存放例項物件。通過-Xms設定初始堆大小,-Xmx設定可擴充套件的最大堆大小。垃圾回收的主要區域。

細分:根據物件存活的週期不同將記憶體分為新生代和老年代。

新生代:可分為Eden空間:From Survivor空間:To Survivor空間,比例為8:1:1 ,可通過-Xmn設定新生代堆大小。新生代頻繁的進行垃圾回收,回收的空間較大, 每次回收都有大批物件死去,只有少量存活。使用複製演算法回收,具體過程:將Eden和From Survivor空間還存活的物件一次性的複製到另外一塊To Survivor空間上,最後清理掉Eden和From Survivor空間。一般場景下,98%的物件可以回收,但不是每次回收都只有不多於10%的物件存活。所以當To Survivor空間空間不足時,需要老年代進行

分配擔保(參考分配策略)

老年代:物件存活率高,老年代只有進行Full GC的時候才進行回收,使用“標記-清理”或者“標記-整理”演算法進行回收。

標記-清理演算法:首先標出需要回收的所有物件,之後統一回收標記的物件。缺點:效率不高,記憶體碎片化。

標記-整理演算法:首先標出需要回收的所有物件,之後讓所有的物件向一端移動,然後清理掉邊界以外的記憶體,避免了記憶體碎片化。

以上就包含了垃圾收集演算法:標記-清理演算法、複製演算法、標記-整理演算法、分代收集演算法。

5.方法區:執行緒共享的區域。存貯已被虛擬機器載入的類資訊、常量、靜態變數、即時編譯器編譯後的程式碼等資料。稱為“永久代”。無法滿足分配需求是,丟擲OOM異常。

6.執行時常量池:方法區的一部分。用於存放編譯器生成的各種字面量和符號引用。

永久代的垃圾回收效率比較低,主要回收兩部分內容:廢棄常量和無用的類。

1)廢棄常量:沒有引用的常量,可以被回收。

2)無用的類滿足:

    類的所有例項都被回收;

    載入類的ClassLoader已經被回收;

    該類對應的java.lang.class物件沒有在任何地方引用,無法再任何地方通過反射訪問類的方法;

7.直接記憶體:不是虛擬機器執行時資料區的一部分,不會受到Java堆大小的限制,但是會受到本機總記憶體大小以及處理器定址空間的限制。

二 Java物件

  一個java類的完整的生命週期會經歷載入、連線、初始化、使用、和解除安裝五個階段,當然也有在載入或者連線之後沒有被初始化就直接被使用的情況。具體可參考 :詳解Java類的生命週期

物件基本上都是在jvm的堆區中建立,在建立物件之前,會觸發類載入(載入、連線、初始化),當類初始化完成後,根據類資訊在堆區中例項化類物件,初始化非靜態變數、非靜態程式碼以及預設構造方法,當物件使用完之後會在合適的時候被jvm垃圾收集器回收。物件的生命週期只是類的生命週期中使用階段的主動引用的一種情況(即例項化類物件)。而類的整個生命週期則要比物件的生命週期長的多。

建立過程:

1)為物件分配空間等於將一塊確定大小的記憶體從Java堆中劃分出來。有兩種方式:

指標碰撞:假設Java堆記憶體是絕對規整的,所有用過的記憶體放在一邊,空閒的在另一邊,中間有一個指標作為分界指示器,那麼所謂分配記憶體就是將指標移動和物件大小相等的距離。

空閒列表:如果Java堆不是規整的,虛擬機器需要維護一個列表,記錄哪些記憶體塊可用,在分配的時候找到足夠大的空間劃分給物件例項,並更新列表上的記錄。

TLAB:(Thread Local Allocation Buffer):每個執行緒預先分配一小塊記憶體,防止多執行緒分配物件時候記憶體衝突。

2)虛擬機器將分配到的記憶體空間初始化為零值。

3)虛擬機器對物件進行必要的設定,例如物件是哪兒個類的例項、如何找到類的元資料資訊、物件的雜湊值、物件的GC年代等。

4)執行<init>方法,按照程式設計師的意願初始化物件,這樣一個真正的物件才算完全可用。

分配策略:

1)大多數情況下,物件在新生代的Eden區中分配,Eden不夠時,發起一次MinorGC。

2)大物件(大量連續記憶體空間的Java物件)直接進入老年代,虛擬機器提供一個引數-XX:PertenureSizeThreshold,大於該閾值的西鄉直接在老年代中分配。

3)長期存活的物件將進入老年代。

4)空間分配擔保:在發生MinorGC之前,虛擬機器先檢查老年代最大可用的連續空間是否大於新生代的物件總和,如果大於,那麼MinorGC可以確保是安全的。如果不成立,那虛擬機器會查案HandlePromotionFailure設定值是否允許擔保失敗。如果允許,那麼會繼續檢查老年代最大可用的連續空間是否大於歷次晉升到老年代物件的平均大小,如果大於,將嘗試進行一次MinorGC,儘管有風險。否則改為進行一次Full GC。

物件回收

有兩種方法判斷物件是否仍在存活:

1)引用計數法:給物件新增一個引用計數器,每當一個地方引用它時,計數器值就加1,引用失效時,計數器減1,任何時刻計數器為0的物件就是不可能再被使用的。簡單,但是無法解決相互迴圈引用的問題。

2)可達性分析演算法:通過一系列的稱為"GC Roots"的物件作為起始點,從這些節點開始向下搜尋,搜多所走過的路徑稱為引用鏈,當一個物件到GCRoots沒有任何引用鏈的時候,證明物件不可用。

即是在可達性分析演算法中不可大的物件,也並非“非死不可”,一個物件要真正宣告死忙,至少要經理兩次標記過程:如果物件不可達,那它第一次標記並且進行一次篩選,篩選條件是是否有必要執行finalize()方法。當物件沒有覆蓋finalize()方法,或者finalize()方法已經被虛擬機器掉用過,虛擬機器將這兩種情況都視為“沒有必要執行”。

如果被判定為有必要執行finalize()方法,那麼物件將會被放置在一個叫F-Queue的佇列之中,之後虛擬機器自動執行finalizer。

三 垃圾收集器

相關推薦

深入理解Java虛擬機器筆記

內容主要參考《深入理解Java虛擬機器(第2版)》 Java和C++之間有一堵由記憶體動態分配和垃圾收集技術所圍成的“高牆”,牆外面的人想進去,牆裡面的人想出來。 一 JVM執行時資料區 執行時資料區結構如下圖: 1 程式計數器:記憶體較小,執行緒執行的位元組碼的行號指

讀書筆記深入理解Java虛擬機器JAVA記憶體區域

  .結構圖來自原書 執行緒私有區域 程式計數器 虛擬機器棧 本地方法棧 所有執行緒共享 方法區 堆   程式計數器(執行緒私有) 是一塊較小的記憶體空間,可以看做是當前執行緒所執行的位元組碼的行號

深入理解java虛擬機器系列java記憶體區域與記憶體溢位異常

文章主要是閱讀《深入理解java虛擬機器:JVM高階特性與最佳實踐》第二章:Java記憶體區域與記憶體溢位異常 的一些筆記以及概括。 好了開始。如果有什麼錯誤或者遺漏,歡迎指出。 一、概述 先上一張圖 這張圖主要列出了Java虛擬機器管理的記憶體的幾個區域。 常有人

讀書筆記深入理解Java虛擬機器物件已死?與記憶體分配策略

物件是否可回收 引用計數演算法 給物件新增一個引用計數器,每當有一個地方引用它時,計數器值就加1;當引用失效時就減1;當等於0時就認為物件不可能再被使用。問題:當兩個物件相互引用時,就無法回收了。 可達性分析演算法 通過一系列的稱為“GC Roots”的物件作為起

讀書筆記深入理解Java虛擬機器物件建立、記憶體佈局、訪問定位

物件的建立 類載入檢查 檢查這個指令的引數是否能在常量池中定位到一個類的引用 檢查這個符號引用代表的類是否已被載入、解析和初始化過, 如果沒有,那必須先執行相應的類載入過程 確定物件所需記憶體的大小 為新生物件分配記憶體 初始化物件的欄位, 大

深入Java虛擬機器筆記Java記憶體區域與記憶體溢位異常

1、程式計數器為很小的記憶體空間,為當前執行緒執行的位元組碼的行號指示器,通過改變計數器的值來選取下一條需要執行的位元組碼指令,迴圈、分支等基礎功能都是需要計數器來完成的 2、Java虛擬機器棧為Java方法執行的記憶體模型,每個方法被執行時都會同時建立棧

深入理解Java虛擬機器》-實戰練習修改class檔案

這是一篇修改class檔案的文章。註釋並不完全,要抓住這次練習的目的: boolean在虛擬機器中是以何種方式解讀的 好的,開始我的表演 1.安裝asmtools.jar(本文尾部有步驟) 2.編寫一個java檔案,並編譯,執行  2.1 Foo.java 1 public

深入理解JVM虛擬機:Java運行時數據區域

字面量 符號 地方 64位 因此 lower 優化 java堆大小 工作 概述 JVM是Java語言的精髓所在,因為它Java語言實現了跨平臺運行,以及自動內存管理機制等,本文將從概念上介紹JVM內存的各個區域,說明個區域的作用。 JVM運行時數據區模型 Java虛擬機在執

深入理解Java虛擬機器筆記---class類檔案魔數,版本,常量池

魔數    每個class檔案的頭4個位元組稱為魔數(Magic Number),其值為:0xCAFEBABE,它的唯一作用是用於確定這個檔案是否為一個能被虛擬機器接受的class檔案。使用魔數而不是副檔名來進行識別主要是基於安全的考慮,因為檔案的副檔名可以隨意地被改動。 版本號

深入理解Java虛擬機器筆記——Java記憶體模型與併發程式設計

  當程式在執行過程中,會將運算需要的資料從主存複製一份到CPU的快取記憶體中,那麼CPU進行計算時就可以直接從它的快取記憶體讀取資料和向其中寫入資料,當運算結束後,再將告訴快取中的資料重新整理到主存中。   如果一個變數在多個CPU中都存在快取,那麼就存在快取一致性

深入理解Java虛擬機器筆記——虛擬機器類載入機制

虛擬機器類載入機制 類載入機制:虛擬機器把描述類的資料從class檔案載入到記憶體,並對資料進行校驗、  轉換解析和初始化,最終形成可以被虛擬機器直接使用的Java型別。 在Java中,型別的載入和連線過程都是在程式執行期間完成的。   類載入時機(類從載入到虛擬

深入理解 Java 虛擬機器筆記虛擬機器位元組碼執行引擎

7.虛擬機器位元組碼執行引擎 執行引擎是 Java 虛擬機器最核心的組成部分之一。在 Java 虛擬機器規範中制定了虛擬機器位元組碼執行引擎的概念模型,這個概念模型成為各種虛擬機器執行引擎的統一外觀(Facade)。不同的虛擬機器實現,執行引擎可能會有解釋執行和編譯執行兩種,有可能兩

深入理解Java虛擬機器筆記--物件的記憶體佈局和訪問定位

物件的記憶體佈局         在HotSpot虛擬機器中,物件在記憶體中儲存的佈局可以分為3塊區域:物件頭(Header)、例項資料(Instance Data)和對齊填充(Padding)。         HotSpot虛擬機器物件頭包括兩部分資訊:第一

深入理解Java虛擬機器筆記--記憶體分配規則

記憶體分配規則         通過在Client模式(也就是採用Serial/SerialOld收集器)下講解幾條最普遍的記憶體分配規則。 物件優先在Eden區分配:在大多數情況下,物件都在Eden區進行分配。當Eden區沒有足夠的空間進行分配時將發起一次M

深入理解 Java 虛擬機器筆記虛擬機器效能監控與故障處理工具

3.虛擬機器效能監控與故障處理工具 定位問題時,知識和經驗是關鍵基礎、資料(執行日誌、異常堆疊、GC日誌、執行緒快照、堆轉儲快照)是依據、工具是運用知識處理資料的手段。 思維導圖 JDK的命令列工具 jps: 虛擬機器程序狀況工具 jps(JVM Proce

深入理解 Java 虛擬機器筆記】類檔案結構

5.類檔案結構 由於最近十年內虛擬機器以及大量建立在虛擬機器之上的程式語言如雨後春筍般出現並蓬勃發展,將我們編寫的程式編譯成二進位制本地機器碼(Native Code)已不再是唯一的選擇,越來越多的程式語言選擇了作業系統和機器指令集無關的、平臺中立的格式作為程式

深入理解java虛擬機器----第十章晚期優化

11.1 概述     在部分的商用虛擬機器(Sun HotSpot、IBM J9)中,Java 程式最初是通過直譯器(Interpreter)進行解釋執行的,當虛擬機發現某個方法或程式碼塊的執行特別頻繁時,就會把這些程式碼認定為“熱點程式碼” (Hot Spot

深入理解Java虛擬機器筆記---volatile變數的特殊規則

   當一個變數定義成volatile之後,它將具備兩種特性:第一是保證此變數對所有執行緒的可見性,這裡的“可見性”是指當一條執行緒修改了這個變數的值,新值對於其它執行緒是可以立即得知的,變數值線上程間傳遞均需要通過主記憶體來完成,如:執行緒A修改一個普通變數的值,然後向主

深入理解Java類載入機制

1 前言: 在上一篇文章一文讓你明白 Java 位元組碼中, 我們瞭解了java位元組碼的解析過程,那麼在接下來的內容中,我們來了解一下類的載入機制。 2 題外話 Java的核心是什麼?當然是JVM了,所以說了解並熟悉JVM對於我們理解Java語言非常重要,不管你是做Java還是Andr

深入理解Java多執行緒

關於java多執行緒的概念以及基本用法:java多執行緒基礎 1,停止執行緒 停止執行緒意味著線上程執行完之前停止正在做的操作,即立刻放棄當前的操作,這並不容易。停止執行緒可以用Thread.stop()方法,但是這個方法不安全,所以不建議使用,還有一個方法就是Thre