()類裝載子系統
裝載 連接 初始化
()方法區被所有線程共享垃圾收集也會清理方法區中的無用類型對象
a 類型信息類加載器加載類時從類文件中提取出來
類的完整有效名
父類的完整有效名(interface and javalangObject 除外因為無父類)
類型的修飾符
類型直接接口列表
b 常量池存儲了一個類型所使用的常量所有類型域和方法的符號引用
c 域信息jvm必須在方法區中保存類型的所有域的相關信息以及域的聲明順序
域的相關信息包括
域名
域類型
域修飾符(public private protected static final volatile transient…)
d方法信息
方法名
方法返回類型
方法參數
方法的修飾符
方法的字節碼(abstract and native 除外)(被PC寄存器指向)
操作數棧和方法棧幀的局部變量區的大小
異常表
e 類的靜態變量(所有對象共享一分拷貝)
f 類的被聲明為final的類變量(所有對象共享一分拷貝)
g 加載一個類的類加載器的引用
h Class類的引用
i 方法表
j 一個例子
Class Lava {
private int speed = ;
void flow();
}
Class Volcano {
public static void main(String[] args) {
Lava lava = new Lava();
lavaflow();
}
}
下面我們描述一下main()方法的第一條指令的字節碼是如何被執行的不同的jvm實現的差別很大這裡只是其中之一
為了運行這個程序你以某種方式把Volcano傳給了jvm有了這個名字jvm找到了這個類文件(Volcanoclass)並讀入它從類文件提取了類型信息並放在了方法區中通過解析存在方法區中的字節碼jvm激活了main()方法在執行時jvm保持了一個指向當前類(Volcano)常量池的指針
注意jvm在還沒有加載Lava類的時候就已經開始執行了正像大多數的jvm一樣不會等所有類都加載了以後才開始執行它只會在需要的時候才加載
main()的第一條指令告知jvm為列在常量池第一項的類分配足夠的內存
jvm使用指向Volcano常量池的指針找到第一項發現是一個對Lava類的符號引用然後它就檢查方法區看lava是否已經被加載了
這個符號引用僅僅是類lava的完整有效名lava這裡我們看到為了jvm能盡快從一個名稱找到一個類一個良好的數據結構是多麼重要這裡jvm的實現者可以采用各種方法如hash表查找樹等等同樣的算法可以用於Class類的forName()的實現
當jvm發現還沒有加載過一個稱為Lava的類它就開始查找並加載類文件Lavaclass它從類文件中抽取類型信息並放在了方法區中
jvm於是以一個直接指向方法區lava類的指針替換了常量池第一項的符號引用以後就可以用這個指針快速的找到lava類了而這個替換過程稱為常量池解析(constant pool resolution)在這裡我們替換的是一個native指針
jvm終於開始為新的lava對象分配空間了這次jvm仍然需要方法區中的信息它使用指向lava數據的指針(剛才指向volcano常量池第一項的指針)找到一個lava對象究竟需要多少空間
一旦jvm知道了一個Lava對象所要的空間它就在堆上分配這個空間並把這個實例的變量speed初始化為缺省值假如lava的父對象也有實例變量則也會初始化
當把新生成的lava對象的引用壓到棧中第一條指令也結束了下面的指令利用這個引用激活java代碼把speed變量設為初始值另外一條指令會用這個引用激活Lava對象的flow()方法
()堆存放運行時所有 對象 和 數組
()棧每次啟動一個新的線程就會被分配一個棧
()PC 寄存器 ( 程序計數器 )
總是指向該線程下一步要執行的指令指令的位置放在方法區的方法字節碼中內容是相 對於第一個指令的偏移量
()本地方法棧
From:http://tw.wingwit.com/Article/program/Java/hx/201311/26491.html