第一章 JAVA體系結(jié)構(gòu)介紹
- java應(yīng)用程序可以使用兩種類裝載器材原,啟動(dòng)(bootstrap)類裝載器和用戶自定義裝載器窿侈。
每一個(gè)類被裝載的時(shí)候念秧,java虛擬機(jī)都監(jiān)視著這個(gè)類,看它是被什么裝載器裝載的聊闯,當(dāng)被裝載的類引用了其他類的時(shí)候工猜,
會(huì)使用相同的類裝載器去裝載被引用的類。因此默認(rèn)情況下只能看到被同一個(gè)類裝載器裝載的類菱蔬,通過(guò)這種方法篷帅,java允許
在java程序中簡(jiǎn)歷多個(gè)命名空間,每一個(gè)類加載器都有自己的命名空間汗销。 -
class
文件,運(yùn)行在JVM上的二進(jìn)制文件
第三章 安全(--看完再回顧本章)
- JAVA沙箱中類裝載體系結(jié)構(gòu)是第一道防線
- 防止惡意代碼干涉善意代碼
- 守護(hù)被信任類庫(kù)的邊界
- 將代碼分類犹褒,確定該類代碼可以執(zhí)行些些操作
- class 文件檢測(cè)器
- 檢驗(yàn)字節(jié)碼的的完整性
- 類型數(shù)據(jù)語(yǔ)義檢查
- 字節(jié)碼驗(yàn)證
- 符號(hào)引用驗(yàn)證
- 二進(jìn)制兼容
- JVM內(nèi)置安全特性
- 類型安全的引用轉(zhuǎn)換
- 結(jié)構(gòu)化的內(nèi)存訪問(wèn)
- 自動(dòng)垃圾收集
- 數(shù)組邊界檢查
- 空引用檢查
- 禁止對(duì)內(nèi)存進(jìn)行非結(jié)構(gòu)化訪問(wèn)
- 異常的結(jié)構(gòu)化處理
- 安全管理器和java api
- 代碼簽名和認(rèn)證抵窒,將一個(gè)未簽名的class文件通過(guò)散列和私鑰得到一個(gè)帶有簽名后散列的文件
- 訪問(wèn)控制器
第五章 java虛擬機(jī)
- 生命周期弛针,main作為函數(shù)的起點(diǎn),每一個(gè)程序都運(yùn)行一個(gè)虛擬機(jī)實(shí)例上李皇。java虛擬機(jī)上兩種線程削茁,一種是守護(hù)線程,另一種是非守護(hù)線程
守護(hù)線程是由jvm自己使用的掉房,比如垃圾回收的線程茧跋,而開始于main函數(shù)的線程是非守護(hù)線程。只要還有非守護(hù)線程在運(yùn)行卓囚,虛擬機(jī)還是存活的
瘾杭,所有非守護(hù)線程退出時(shí),虛擬機(jī)會(huì)自動(dòng)退出哪亿。
java 虛擬機(jī)的結(jié)構(gòu)體系
-------------------
| 類裝載器子系統(tǒng) |
-------------------
|
------------------------------------------------------------------
| | | | | | |
| 方法區(qū) 堆 java棧 PC寄存器 本地方法棧 |
------------------------------------------------------------------
| |
執(zhí)行引擎 ————————————————> 本地方法接口
- 一些點(diǎn)
- 方法區(qū)和堆內(nèi)存是由所有的線程共享的粥烁,虛擬機(jī)裝載class文件時(shí),會(huì)把類的數(shù)據(jù)放在方法區(qū)中蝇棉,當(dāng)程序運(yùn)行時(shí)讨阻,會(huì)把根據(jù)類數(shù)據(jù)創(chuàng)建的對(duì)象
放在堆內(nèi)存中。 - 當(dāng)新線程被創(chuàng)建時(shí)篡殷,都將得到一個(gè)
PC寄存器
和一個(gè)JAVA棧
钝吮,PC寄存器
總是指向下一條被執(zhí)行的指令,java棧則存儲(chǔ)方法的調(diào)用狀態(tài)。(局部變量
,參數(shù)
奇瘦,返回值
,運(yùn)算中間值
) - java 棧是有很多的棧幀組成棘催,當(dāng)線程調(diào)用一個(gè)方法的時(shí)候,链患,JVM將新的棧幀入棧巧鸭,當(dāng)函數(shù)返回時(shí),棧幀被出棧麻捻。
- 數(shù)據(jù)類型
- 基本類型(float, double, byte, short, int, long, char, boolean, returnAddress)
64 32 8 16 32 64 16 - 引用類型(類纲仍,接口 ,數(shù)組)
方法區(qū)
- 方法區(qū)的數(shù)據(jù)共享贸毕,因此是必須線程安全的郑叠。虛擬機(jī)允許程序員指定方法區(qū)的大小
- 方法區(qū)會(huì)在內(nèi)存中存儲(chǔ)類的以下信息:
類型的全限定名(包名+.+類名)
此類超類的全限定名
類還是接口
修飾符(public ,abstruct, final)
接口全限定名的有序列表
類型的常量池
字段信息(字段名,類型明棍,修飾符)
方法信息(方法名乡革,類型,修飾符)
一個(gè)到類ClassLoder的引用
一個(gè)到Class類的引用(forName()摊腋,讓用戶得到已裝載對(duì)象的Class實(shí)例)
方法字節(jié)碼
操作數(shù)棧和該方法在棧幀中局部變量的大小
異常表
下面看一看流程
class Volcano(){
public static void main(String args[]){
Lava lava = new Lava();
lava.flow();
}
}
- 例如我們要執(zhí)行一個(gè)叫
Volcano
的類沸版,當(dāng)我們告訴JVMVolcano
這個(gè)名字
- JVM會(huì)找到并讀入
Volcano.class
文件 - 然后導(dǎo)入其中的二進(jìn)制流,并把相應(yīng)的數(shù)據(jù)存在方法區(qū)
- 通過(guò)執(zhí)行方法區(qū)中的字節(jié)碼兴蒸,開始執(zhí)行main()方法视粮,在執(zhí)行時(shí)會(huì)一直持有指向常量池的指針
- main方法中第一條指令是給常量池第一個(gè)類分配象的內(nèi)存,于是在常量池中找到第一項(xiàng)橙凳,發(fā)現(xiàn)是對(duì)另一個(gè)類Lava的引用
- 檢查方法區(qū)蕾殴,看是否被裝載,發(fā)現(xiàn)沒有被裝載岛啸,于是查找
Lava.class
文件裝載钓觉,同樣把信息存儲(chǔ)在方法區(qū)中 - 接著指向常量池第一行的指針替換掉常量池的第一項(xiàng)(
Lava
的全限定名)->常量池的解析
(符號(hào)引用替換成直接引用,本地指針) - 虛擬機(jī)準(zhǔn)備為L(zhǎng)ava分配內(nèi)存,并用這個(gè)指針訪問(wèn)它的類信息坚踩,找出類信息中的需要為這個(gè)類分配多少堆內(nèi)存
- 虛擬機(jī)確定了大小荡灾,就在堆上為對(duì)象分配內(nèi)存,并初始化常量值瞬铸。然后把對(duì)象的引用入棧批幌,第一條指令執(zhí)行完成。
- 接下來(lái)通過(guò)這個(gè)引用調(diào)用flow方法
堆
java一個(gè)虛擬實(shí)例中只有一個(gè)堆空間赴捞,所有線程共享
java 只有在堆中分配內(nèi)存的指令逼裆,沒有釋放的指令,垃圾收集器會(huì)負(fù)責(zé)堆和方法區(qū)的內(nèi)存回收
堆和方法區(qū)一樣也不是一個(gè)連續(xù)的內(nèi)存區(qū)赦政,是可擴(kuò)展的
堆上的對(duì)象還有一部分?jǐn)?shù)據(jù)胜宇,是對(duì)象鎖(互斥鎖)耀怜,請(qǐng)求可以追加,請(qǐng)求幾次桐愉,必須釋放幾次财破,例如請(qǐng)求了4次,只釋放了3次从诲,那還是持有這個(gè)對(duì)象鎖左痢。
堆上對(duì)象還有一部分?jǐn)?shù)據(jù)與垃圾收集器有關(guān),垃圾回收器必須跟蹤每個(gè)對(duì)象系洛。
數(shù)組是一個(gè)對(duì)象俊性,總是存儲(chǔ)在堆中
PC(程序計(jì)數(shù)器)寄存器,在每個(gè)線程中有一個(gè)描扯,它有一個(gè)字的大小定页,存儲(chǔ)一個(gè)本地指針,總是指向下一條將要執(zhí)行的指令绽诚。
java 棧
- 每當(dāng)啟用一個(gè)線程典徊,JVM會(huì)為它分配一個(gè)java 棧。
- 棧幀的組成
- 局部變量區(qū) -> 一個(gè)數(shù)組恩够,以字(32bit)為單位卒落,類型int,float,returnAddress的值再數(shù)組中占一項(xiàng),byte,short,char會(huì)被轉(zhuǎn)化成int,也占一項(xiàng)蜂桶,double,long占2項(xiàng)儡毕。任何一個(gè)實(shí)例方法(非static),的數(shù)組第一項(xiàng)都是對(duì)象本身的reference.
- 操作數(shù)棧 -> byte,short,char會(huì)被轉(zhuǎn)化成int,和上面一樣屎飘,只有在存回堆中是會(huì)被轉(zhuǎn)化為原來(lái)類型妥曲。他也是一個(gè)數(shù)組贾费,但是按照棧操作來(lái)訪問(wèn)钦购。由于java虛擬機(jī)沒有寄存器,java的指令是通過(guò)操作數(shù)棧中取得操作數(shù)的褂萧。
- 棧幀數(shù)據(jù)押桃,支持常量池的解析正常方法返回和異常派發(fā)機(jī)制的數(shù)據(jù)。
為了處理執(zhí)行期的異常退出情況导犹,幀數(shù)據(jù)區(qū)保存一個(gè)對(duì)此方法的異常表的引用唱凯。當(dāng)方法拋出異常,會(huì)在異常表中查找對(duì)應(yīng)的異常谎痢,如果找到了匹配的catch語(yǔ)句磕昼,就會(huì)交給ccatch中的代碼處理,如果沒有則異常中止节猿。 -
兩站不同的虛擬機(jī)實(shí)現(xiàn)的幀分配
- 本地方法棧票从,取決于設(shè)計(jì)者的實(shí)現(xiàn)
執(zhí)行引擎(沒看太明白)
- 運(yùn)行中java程序的每一個(gè)線程都是一個(gè)獨(dú)立的虛擬機(jī)執(zhí)行引擎的實(shí)例漫雕。
- 從線程的生命周期開始,它要么在執(zhí)行字節(jié)碼峰鄙,要么在執(zhí)行native方法浸间。
- 指令集,指令集關(guān)注的中心是操作數(shù)棧吟榴。操作數(shù)棧中的數(shù)值必須按照適合他們類型的方式使用魁蒜。比如壓入棧4個(gè)
int
,卻把他們當(dāng)做兩個(gè)long
來(lái)做操作吩翻,是非法的 兜看。
第六章 JAVA class文件 (粗略看)
java class文件是對(duì)java程序二進(jìn)制文件的精確定義。一個(gè)class文件中指包括一個(gè)class 或者interface.
class文件不一定與java語(yǔ)言有關(guān)狭瞎,別的語(yǔ)言也可以編譯成class文件在虛擬機(jī)上運(yùn)行铣减。
- class 文件組成
- magic ,每個(gè)class文件的前四個(gè)字節(jié) 0xCAFEBABE,用來(lái)分辨是否是class文件脚作。
- minor_version major_version b版本號(hào)葫哗。
- constant_pool_count 常量池的數(shù)量,constant_pool 常量池
- access_flags 類的修飾信息,public ,private ,static 等
- this_class 指向常量池的索引
- super_class 超類常量池索引
第七章 類型的生命周期
- 類主動(dòng)裝載的時(shí)機(jī)
- 創(chuàng)建實(shí)例時(shí)(new, 反射球涛,克隆劣针,反序列化)
- 調(diào)用類中的靜態(tài)方法
- 使用類或接口的靜態(tài)字段或者對(duì)字段賦值(final 修飾的靜態(tài)變量除外,它被初始化為一個(gè)編譯時(shí)的常量表達(dá)式)
- 調(diào)用api反射方法
- 初始化子類
- 含有main函數(shù)的類
- 所有類的初始化都要求它的超類在此之前初始化了亿扁。(接口不是)
- 裝載
- 通過(guò)完全限定名產(chǎn)生一個(gè)二進(jìn)制流
- 解析二進(jìn)制文件
- 創(chuàng)建一個(gè)該類型Class實(shí)例
- 初始化
- 所有類變量初始化語(yǔ)句和類型的靜態(tài)初始化器都被java編譯器收集到一起放在一個(gè)特殊的方法<clinit>中捺典,并非所有的類都有這個(gè)方法。
- 如果多個(gè)線程需要初始化一個(gè)類从祝,僅僅允許一個(gè)線程來(lái)執(zhí)行初始化襟己,其他線程需要等待。完成后需要通知其他等待線程牍陌。
對(duì)象生命周期
- 實(shí)例化
new
reflect.newInstance()
clone()
ObjectInputStream.getObject
堆中分配內(nèi)存擎浴,然后賦予實(shí)例變量初始值
類型當(dāng)沒有引用的時(shí)候會(huì)被卸載,同樣通過(guò)垃圾回收器毒涧。