JVM學習筆記之JVM運行時數據區

JVM運行時數據區可以用下圖表示

概述:其中虛線框內(程序計數器、Java虛擬機棧、本地方法棧)是線程私有的內存空間,只存在於線程的生命週期內,線程結束之後就會消失,因此不需要對這三個區域進行垃圾回收。
堆和方法區是線程共享的數據區,垃圾收集主要是針對堆和方法區進行。

在這裏插入圖片描述

程序計數器

可以看作是當前線程執行的字節碼的行號指示器,記錄正在執行的虛擬機字節碼指令的地址(如果正在執行本地方法,則記錄值爲空)

Java虛擬機棧

每個Java方法執行的同時會創建一個棧幀存放到Java虛擬機棧中,用於存儲局部變量、操作數棧、動態鏈接、方法出口等信息。從方法調用直至執行完成的過程,對應着一個棧幀在 Java 虛擬機棧中入棧和出棧的過程。在這裏插入圖片描述
可以通過 -Xss 這個虛擬機參數來指定每個線程的 Java 虛擬機棧內存大小,在 JDK 1.4 中默認爲 256K,而在 JDK 1.5+ 默認爲 1M:

java -Xss2M HackTheJava

該區域可能拋出以下異常:

  • 當線程請求的棧深度超過最大值,會拋出 StackOverflowError 異常;
  • 棧進行動態擴展時如果無法申請到足夠內存,會拋出 OutOfMemoryError 異常。

本地方法棧

本地方法棧與虛擬機棧類似,它們之間的區別是本地方法棧爲本地方法服務。
本地方法一般用非Java語言(C、C++等)編寫,並且編譯爲基於本機硬件和操作系統的程序,對待這些方法需要特別處理。但也有一些虛擬機吧本地方法棧合併到Java虛擬機棧中(如Sun HotSpot,Sun公司的一個HotSpot實現)
在這裏插入圖片描述

所有對象(包括String)都在這裏分配內存,是垃圾收集的主要區域(“GC 堆”)。

現代的垃圾收集器基本都是採用分代收集算法,其主要的思想是針對不同類型的對象採取不同的垃圾回收算法。可以將堆分成兩塊:

新生代(Young Generation)
老年代(Old Generation)
堆不需要連續內存,並且可以動態增加其內存,增加失敗會拋出 OutOfMemoryError 異常。

可以通過 -Xms 和 -Xmx 這兩個虛擬機參數來指定一個程序的堆內存大小,第一個參數設置初始值,第二個參數設置最大值。

java -Xms1M -Xmx2M HackTheJava

方法區

用於存放已被加載的類信息、常量、靜態變量、即時編譯(JIT)後的代碼等數據。
和堆一樣不需要連續內存,並且可以動態拓展,動態拓展失敗一樣會拋出OutOfMemoryError異常。
對於這塊區域進行垃圾回收的主要目標是對常量池的回收和對壘的卸載,但是一般實現比較困難。
HotSpot虛擬機把它當作永久代進行垃圾回收,但是很難確定永久代的大小,因爲他受到很多因素的影響,並且每次Full GC之後永久代的大小都會改變,從JDK1.8開始,一處永久代,並把方法區移至元空間,它位於本地內存中,而不是虛擬機內存中。
方法區是一個JVM規範,永久代與原空間都是其一種實現方式。在JDK1.8之後,原來永久代的數據被分到了堆和元空間中,元空間存儲類的的元信息靜態變量和常量池放入堆中。

方法區中的常量池

運行時常量池是方法區的一部分。

Class 文件中的常量池(編譯器生成的字面量和符號引用)會在類加載後被放入這個區域。

除了在編譯期生成的常量,還允許動態生成,例如 String 類的 intern()。

直接內存

在 JDK 1.4 中新引入了 NIO 類,它可以使用 Native 函數庫直接分配堆外內存,然後通過 Java 堆裏的 DirectByteBuffer 對象作爲這塊內存的引用進行操作。這樣能在一些場景中顯著提高性能,因爲避免了在堆內存和堆外內存來回拷貝數據。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章