深入分析Java虛擬機

Java虛擬機是相對於物理機的概念,也就是對現有馮諾依曼體系結構的硬件系統的抽象,現有計算機硬件系統是由輸入,運算器、控制器、存儲器和輸出構成的。Java虛擬機則是建立在硬件系統之上,提供自己的規範,使在虛擬機上運行的程序具有跨平臺、自動回收內存等諸多特性。

虛擬機內存劃分概述

Java虛擬機對內存劃分爲5種不同的區域,分別是棧內存、本地方法棧、堆內存、方法區、程序計數器。

棧內存

棧內存是線程私有的,它隨着線程的創建而創建,隨着線程的銷燬而銷燬,在執行方法時會創建棧幀,棧幀中存放的是局部變量表(方法的參數以及局部變量)、操作數棧(指令所操作的數據存放處)等信息。方法的調用就是棧幀入棧的過程。

本地方法棧

執行Native方法時所用到的存儲單元

堆內存

堆內存是線程共享的,當虛擬機啓動時便會創建。該內存區域是用來存放對象實例的,也是垃圾收集器管理的主要區域。

方法區

方法區是線程共享的內存區域,它存儲的主要是在類加載時產生的數據,可以理解爲是存儲Class文件信息或者是類相關信息的。所以編譯後的字節碼、常量、靜態變量等與對象無關只有類有關的數據都放在這裏。

程序計數器

程序計數器作爲線程執行時的行號指示器,分支、跳轉、循環都是通過它實現的,在任一時刻,一個處理器核都只會執行一條線程中的指令,每一個核對應一個程序計數器。

Class文件詳解

Java原碼中的各種變量,關鍵字和運算符號的語義最終都是由多條字節碼命令組合而成的,而ava原碼通過編譯器編譯爲虛擬機可加載的Class文件,Class文件中包含了Java字節碼和符號表和其他輔助信息。

Class文件是一組以8位字節爲原子單位的二進制流,各個數據嚴格按照規定的順序緊湊的排列(順序中包含着信息),而Class文件只包含兩種數據類型:

無符號數 – 表示數字、索引引用、數量值、或按照UTF-8表示字符串,通過u1、u2、u4表示1字節2字節4字節

表 – 是由多個無符號數組成的複合結構,所有表都以"_info"結尾

類型 名稱 描述 數量
u4 magic 魔數 1
u2 minor_version 副版本號 1
u2 major 主版本號 1
u2 constant_pool_count 常量池數量 1
cp_info constant_pool 常量池 常量池數量-1
u2 access_flags 訪問標識 1
u2 this_class 類索引 2
u2 super_class 父類索引 2
u2 interfaces_count 接口數量 1
u2 interfaces 接口索引集合 接口數量
u2 fields_count 字段數量 1
field_info fields 字段表 字段數量
u2 methods_counts 方法數量 1
method_info methods 方法表 方法數量
u2 attributes_count 屬性數量 1
attributes_info attributes 屬性表 屬性數量

魔數以及版本號

Class文件的前4個字節是魔數它的唯一作用就是確定這個文件是Class文件,接下來2個字節是副版本號,再接下來兩個字節是主版本號,用來確定版本號。

常量池數量

由於每個Class文件的常量數量不是固定的,所以緊接着主版本號後面的是常量池數量,用來確定常量的數量

常量池

根據常量池的數量,後面是常量的具體內容,常量池中包含兩大類常量:

  1. 字面量:字面量就是沒有特殊意義的常量,就是用來表示常量,比如文本字符串(字段名等),或是被final修飾的常量值等

  2. 符號引用包括以下三類

類和接口的全限定名(用來確定類和接口)

字段名稱和描述符(用來確定字段及字段的其他信息)

方法名稱和描述符(用來確定字段及字段的其他信息)

類型 標識 描述
CONSTONT_utf8_info 1 utf8編碼字符串
CONSTONT_Integer_info 3 整型字面量
CONSTONT_Float_info 4 浮點型字面量
CONSTONT_Long_info 5 長整型字面量
CONSTONT_Double_info 6 雙精度浮點型字面量
CONSTONT_Class_info 7 類或者接口的符號引用
CONSTONT_String_info 8 字符串類型字面量
CONSTONT_Fieldref_info 9 字段的符號引用
CONSTONT_Methodref_info 10 方法的符號應用
CONSTONT_InterfaceMethodref_info 11 接口方法的符號應用
CONSTONT_NameAndType_info 12 字段或方法的部分引用
CONSTONT_MethodHandle_info 15 方法的句柄
CONSTONT_MethodType_info 16 方法的類型
CONSTONT_InvokeDynamic_info 18 動態方法調用點

常量池中的數據是以_info結尾,前面講到Class文件只有兩種類型,無符號數和表,而常量池的數據全部都是表,也就是由多個無符號數組成的複合結構。

常量池是提供其他表進行引用的,一個class文件中的所有出現的字符都該在常量池中顯示

訪問標識

在常量池結束之後,接着的是2個字節的訪問標識,用於識別該文件是類還是接口、是否爲public、是否爲abstract等信息

類索引、父類索引、接口索引集合

在訪問標識後的爲類索引,是這個類的的全限定名,指向常量池中的CONSTONT_Class_info

字段表和方法表

字段表用於表述接口或者類中聲明的變量。

類型 名稱 描述
u2 access_flags 描述字段、方法作用域等信息
u2 name_index 字段、方法簡單名稱常
u2 descriptor_index 字段、方法描述符
u2 attributes_count 屬性數量
attributes_info attributes 屬性表

屬性表

屬性表的作用是對其他表額外進行描述,下面是一些常用的屬性。

名稱 使用位置 描述
code 方法表 編譯後的字節碼指令
Exceptions 方法表 方法拋出的異常

其中code屬性非常重要,如果把Java程序中的信息分爲代碼和元數據兩部分,那麼Code屬性就是用來描述代碼的,其他所有數據項都是用來描述元數據。

虛擬機類加載過程

虛擬機類加載過程就是將原來磁盤中的代碼加載到內存中。

類加載過程生命週期

類加載的生命週期包括:加載、驗證、準備、解析、初始化、使用、卸載。

其中加載、驗證、準備、初始化、卸載這五個過程順序是確定的,而解析階段有可能在初始化前也有可能在初始化後,在初始化前的解析是靜態綁定(前期綁定),也就是可以在編譯時確定,而初始化後的解析是動態綁定(後期綁定)。

加載
  1. 通過類的全限定名來獲取類的二進制流
  2. 將類加載到方法區中
  3. 生成這個類的Class對象,獲取方法區數據的入口(反射時會使用的)
驗證

驗證合法性

準備

分配類變量內存,並且賦初值

解析

將運行時常量池(類文件中的常量池加載到方法區)的符號引用替換爲直接引用(內存地址)。

初始化

執行方法,爲準備階段類變量的初值賦值。方法是編譯器自動生成的,相當於爲靜態字段賦值的方法,並且會合並static{}代碼塊的代碼。(加載階段還爲涉及到具體對象)

類加載器

上面的生命週期是由類加載器完成的,對於任何一個類,都需要通過類加載器和這個類來確定在JVM中的唯一性。(同一個類不同類加載器加載後的Class對象的equals()方法返回false)

雙親委派機制

如果有一個類加載器收到加載請求,它首先會請求父加載器去加載,所以會導致所有加載請求都會到頂層的啓動類加載器去;當父加載器無法完成加載請求(搜索範圍沒有這個類),就傳遞給子加載器加載。

字節碼執行過程

字節碼源代碼進過編譯又經過類加載器加載到方法區中的,字節碼的執行代表着程序運行時一個方法的執行。

運行時棧幀

棧幀是方法執行時的數據結構,主要包括:局部變量表、操作數棧、動態連接、方法返回地址等。

局部變量表

用來存放方法參數和方法的變量的存儲空間。它的大小在編譯期間就已經確定,存放到Code屬性中。

操作數棧

當方法開始執行時,操作數棧是空的,方法執行過程根據字節碼會往操作數棧中寫入和提取內容。

動態連接

每個棧幀都包含一個指向運行時常量池中所屬方法的引用,這個引用是爲了完成方法調用過程中的動態連接(確定方法),其中靜態方法和私有方法是編譯器可知,運行期不可變的。所以在編譯期就可以確定。如重載就是需要動態連接來確認的

方法返回地址

就是方法的返回地址。。。。。

垃圾回收機制

垃圾回收是回收堆內存中不使用的對象。

判斷對象是否存活

  1. 引用計數算法
    每當有一個地方引用對象就將計數加1,當引用失效就減1,當計數器爲零就說明對象不再被使用了。(無法解決對象循環引用)
  2. 可達性算法
    通過一系列GC Root 對象作爲起點,當一個對象到GC Root 沒有任何引用鏈相連就證明對象不可使用

垃圾收集算法

  1. 標記清除算法
    標記需要回收的對象,之後統一回收。(會產生內存碎片)
  2. 複製算法
    將內存二等分,每次使用一半,當一半內存使用完之後觸發複製算法,將存活的對象複製到另外一半中。(內存縮小到原來的一半)。
    適用於新生代,大量對象死去,少量存活,移動很少的對象。
  3. 標記整理
    標記需要回收的對象,將所有存活對象移動到一端,清除邊界意外的內存。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章