《JVM》(四)Class類文件結構,對象的創建
class文件是一組以8字節為單位的二進制流,只有兩種數據類型:無符號數(基本數據類型),表(復合數據類型)
魔數
版本號
常量池(占class空間最大的數據之一,從1開始計數)
1.字面量 :接近於java層面的常量概念,如字符串,聲明為final的常量
2.符號引用:類和接口的全限定名,字段和方法的描述符
字段描述符:描述字段數據類型
方法描述符:描述方法參數列表和返回值
訪問標誌
類索引,父類索引,接口索引集合
字段表集合(描述接口或類中聲名的變量,不包括方法中的局部變量)
方法表集合
屬性表集合(如,方法表,屬性表都可以帶有自己的屬性表,如code屬性存方法的代碼信息)
對象的創建(非Class類對象)
0.準備工作,這個指令的參數是否可以在常量池中定位到一個類的符號引用,檢查這個類是否已經被加載,解析初始化,如果沒有,先執行相應的類加載過程
1.分配內存(堆中)
2.分配的內存空間都初始化為零值
3.init根據程序員的意願初始化
分配內存
對象所需內存的大小在類加載完成後便完全確定(JVM可以通過普通Java對象的類元數據信息確定對象大小);
為對象分配內存相當於把一塊確定大小的內存從Java堆裏劃分出來
1. 指針碰撞
如果Java堆是絕對規整的:一邊是用過的內存,一邊是空閑的內存,中間一個指針作為邊界指示器;
分配內存只需向空閑那邊移動指針,這種分配方式稱為"指針碰撞"(Bump the Pointer);
2. 空閑列表
如果Java堆不是規整的:用過的和空閑的內存相互交錯;
需要維護一個列表,記錄哪些內存可用;
分配內存時查表找到一個足夠大的內存,並更新列表,這種分配方式稱為"空閑列表"(Free List);
Java堆是否規整由JVM采用的垃圾收集器是否帶有壓縮功能決定的;
所以,使用Serial、ParNew等帶Compact過程的收集器時,JVM采用指針碰撞方式分配內存;而使用CMS這種基於標記-清除(Mark-Sweep)算法的收集器時,采用空閑列表方式;
對象的訪問定位
1.通過句柄訪問對象
好處:reference中存的是穩定的句柄地址,在GC時對象被移動只會改變實例數據指針,而reference本身不需要改變
2.通過直接指針訪問對象
好處:訪問速度快
對象創建的時機
使用new關鍵字創建對象
使用Class類的newInstance方法(反射機制)
用Constructor類的newInstance方法(反射機制)
使用Clone方法創建對象
用(反)序列化機制創建對象
對象的初始化順序
父類靜態代碼塊,靜態成員變量
子類靜態代碼塊,靜態成員變量
父類普通成員變量,非static代碼塊
父類構造函數
子類普通成員變量,非static代碼塊
子類構造函數
類加載的時機
new關鍵字實例化對象,讀取或設置一個類的靜態字段(被final修飾除外)、調用一個類的靜態方法;
使用java.lang.reflect包的方法對類進行反射調用
初始化一個類,若其父類沒有被初始,先初始化起父類
虛擬機啟動時,執行的主類(含main方法的類)先初始化
比如,new一個對象,首先檢查Class類是否被加載,沒有,先進行類加載過程;
然後進行對象的創建,分配內存,按照順序初始化;
再次new一個對象,檢查Class類被加載過了,直接進行對象的創建;
《JVM》(四)Class類文件結構,對象的創建