1. JVM體系結構
- “對象的引用”在棧里面
- 真正對象的“數(shù)據(jù)”在堆里面
2.類加載器及雙親委派機制
類加載器
作用:加載class文件
類是模板厨埋,對象是具體的
public class Test {
public static void main(String[] args) {
//類是模板妓柜,對象是具體的
Class<Test> testClass = Test.class;
}
}
test1剧蚣,test2鸡岗,test3 三個對象都是類模板new出來的瓶竭,通過第一次輸出可以知道外遇,三個對象是不一樣的榴都。
但是他們getClass后輸出的結果就是一樣的湖员,因為getClass得到的是類的模板
加載器的分類
- 虛擬機自帶的加載器
- 啟動類(根)加載器 BOOT
- 擴展類加載器 EXC
- 應用程序(系統(tǒng)類)加載器 APP
雙親委派機制
APP ---> EXC ---> BOOT
BOOT中不存在 ---> EXC中不存在 ---> APP(當前應用)
雙親委派模型的工作流程是:如果一個類加載器收到了類加載的請求娘摔,它首先不會自己去嘗試加載這個類窄坦,而是把請求委托給父加載器去完成,依次向上凳寺,因此,所有的類加載請求最終都應該被傳遞到頂層的啟動類加載器中肠缨,只有當父加載器在它的搜索范圍中沒有找到所需的類時,即無法完成該加載晒奕,子加載器才會嘗試自己去加載該類闻书。
1吴汪、當 AppClassLoader加載一個class時蒸眠,它首先不會自己去嘗試加載這個類楞卡,而是把類加載請求委派給父類加載器ExtClassLoader去完成。
2蒋腮、當 ExtClassLoader加載一個class時池摧,它首先也不會自己去嘗試加載這個類,而是把類加載請求委派給BootStrapClassLoader```去完成膘魄。
3、如果 BootStrapClassLoader加載失敶雌稀(例如在 $JAVA_HOME/jre/lib里未查找到該class),會使用 ExtClassLoader來嘗試加載洛波;
4骚露、若ExtClassLoader也加載失敗,則會使用 AppClassLoader來加載闻伶,如果 AppClassLoader也加載失敗,則會報出異常 ClassNotFoundException蓝翰。
舉個例子
我們模擬Java中l(wèi)ang包下的String類女嘲,它一直會詢問自己的父加載器有沒有這個類,恰好BOOT中有這個類爆雹,但是其中沒有main方法愕鼓,就會報錯。
假如是換一個名字册倒,根加載器中沒有這個Student類磺送,那么它就能正常加載成功。
3、native關鍵字
凡是被native修飾的馅袁,說明java的作用范圍達不到了,會去調用c犹褒,c++語言的庫!
以“start0();”方法為例
- 調用被native關鍵字修飾的方法估脆,會進入本地方法棧
- 然后會調用本地方法的本地方法接口(JNI)
- JNI的作用:擴展java的使用座云,融合不同的編程語言為java所用!最初是c/c++
- java誕生的使用圃阳,c/c++很流行璧帝,想要立足,就必須要用c/c++的程序
- 因此锣夹,它在內存區(qū)域中專門開辟了一塊標記區(qū)域Native Method Stack苏潜,來登記native方法
- 在最終執(zhí)行的時候,通過JNI(本地方法接口)來加載本地方法庫中的方法
- 平常用不到這類的方法贴唇,該方法多操控硬件資源
4飞袋、PC寄存器
程序計數(shù)器:Program Counter Register(PC計數(shù)器或者指令計數(shù)器更貼切):
-每個線程都有一個程序計數(shù)器,是線程私有的巧鸭,就是一個指針蹄皱,指向方法區(qū)中的方法字節(jié)碼(用來存儲指向下一條指令的地址,即將要執(zhí)行的指令代碼)巷折,在執(zhí)行引擎讀取下一條指令锻拘,是一個非常小的內存空間,幾乎可以忽略不計
如果正在執(zhí)行的是本地(Native)方法署拟,這個計數(shù)器值則應為空(Undefined)
5推穷、方法區(qū)
方法區(qū) Method Area:
- 又被稱為靜態(tài)區(qū),它跟堆一樣被所有線程共享
- 它用于存儲已被虛擬機加載的類型信息馒铃、常量、靜態(tài)變量娃殖、即時編譯器編譯后的代碼緩存等數(shù)據(jù)
- 方法區(qū)中包含的都是整個程序中永遠唯一的元素议谷,如:class、static變量芬首。
6逼裆、棧
棧(先進后出):也叫棧內存,主管程序的運行艺晴,它的生命周期和線程同步掸屡;線程結束,棧內存也就釋放了狈究;對于棧來說盏求,不存在垃圾回收問題;一旦線程結束磅废,棧就“Over”荆烈;
- 每個線程都包含一個棧區(qū)竟趾,棧中只保存基本數(shù)據(jù)類型的值和對象以及基礎數(shù)據(jù)的引用宫峦。(8大基本類型+對象引用+實例的方法)
- 每個棧中的數(shù)據(jù)(基本數(shù)據(jù)類型和對象的引用)都是私有的,其它棧是無法進行訪問的犀勒。
- 棧分為三個部分:基本類型變量區(qū)妥曲、執(zhí)行環(huán)境上下文、操作指令區(qū)(存放操作指令)铸本。
棧運行原理:棧幀遵堵,程序正在執(zhí)行的方法一定在棧的頂部
什么是棧溢出:(StackOverflowError)
package com.my.test;
//理解什么叫棧溢出
//為什么main()方法先執(zhí)行后結束
public class Test03 {
public static void main(String[] args) {
Test03 test03 = new Test03();
test03.a();
}
public void a(){
b();
};
public void b(){
a();
};
}
7陌宿、三種JVM
- sun公司的HotSpot(Java HotSpot(TM) 64-Bit Server VM (build 25.152-b16, mixed mode))
- Oracle公司的 JRockit
- IBM J9 VM
8、堆(Heap)
Java堆(Java Heap)是虛擬機所管理的內存中最大的一塊舶得。Java堆是被所有線程共享的一塊內存區(qū)域爽蝴,在虛擬機啟動時創(chuàng)建。此內存區(qū)域的唯一目的就是存放對象實例九孩,Java世界里“幾乎”所有的對象實例都在這里分配內存发框。
Java堆是垃圾收集器管理的內存區(qū)域,因此它也被稱作“GC堆”宪拥。
一個JVM只有一個堆內存铣减,堆內存的大小是可以調節(jié)的。
堆內存中細分為三個領域:
- 新生區(qū)(伊甸區(qū))young/new
- 養(yǎng)老區(qū)old
-
永久區(qū)perm
image.png
GC垃圾回收:主要在伊甸園區(qū)和養(yǎng)老區(qū)
“OOM”:內存滿了犁河,堆內存不夠
JDK8以后永久存儲區(qū)更名為“元空間”
新生區(qū)
- 類:誕生和成長以及死亡的地方
- 伊甸園區(qū):所有的對象都是由伊甸園區(qū)new出來的
永久區(qū)
- 概念:
這個區(qū)域常駐內存桨螺,用來存放JDK自身攜帶的Class對象酿秸、interface元數(shù)據(jù)、存儲的是java運行時的一些環(huán)境或者類信息
這個區(qū)域不存在垃圾回收肝箱;除非關閉虛擬機才會釋放這個區(qū)域的內存