1.JVM位置
Jdk包含jre+開發(fā)工具耸棒,jre包括了jvm+java標準類庫。簡單來說,jvm保證了Java的跨平臺性婚温,只要在不同的操作系統(tǒng)安裝了jvm(Java虛擬機)就可以將java字節(jié)碼(.java)編譯成相同的字節(jié)碼文件(.class)。jre(java runtime environment)負責運行java已編譯程序所必須的軟件環(huán)境媳否,不能將java源代碼編譯成字節(jié)碼文件栅螟。jdk可以創(chuàng)建、編譯篱竭、運行java程序力图。
2.JVM的體系結構
3.類加載器
1.虛擬機自帶的加載器
2.啟動類(根)加載器Boot
3.擴展類加載器ExtClassLoader
4.應用程序加載器AppClassLoader
4.雙親委派機制
1.類加載器收到類加載的請求
2.將這個請求向上委托給父類加載器去完成,一直向上委托掺逼,直到啟動類加載器
3.啟動類加載器檢查是否能夠加載這個類搪哪,能加載就結束、否則拋出異常坪圾,通知子加載器進行加載
4.重復步驟3
5.沙箱安全機制
沙箱是一個限制程序運行的環(huán)境晓折,沙箱機制就是將Java代碼限定在虛擬機特定的運行范圍中,并且嚴格限制代碼對本地資源的訪問兽泄,通過這樣的措施來保證對代碼的有效隔離漓概,防止對本地系統(tǒng)造成破壞,沙箱主要限制系統(tǒng)資源(CPU病梢、內存胃珍、文件系統(tǒng)、網絡)訪問蜓陌,不同級別的沙箱對這些資源訪問的權限也可以不一樣觅彰。
現(xiàn)在的安全模型就是,jvm給不同的代碼分配不同的域钮热,該代碼就擁有這個域所擁有的對于本地資源的全部權限填抬。(域類似于角色)
沙箱安全機制的組成部分:
1.字節(jié)碼校驗器:它保證java代碼符合java語言規(guī)范,核心類由于已經校驗過了封裝好的隧期,字節(jié)碼不會校驗核心類
2.類加載器飒责,類加載器是利用了雙親委派機制,它保證了好的代碼不會被壞的代碼污染 它定義了被信任類庫的邊界 為代碼歸入域(類似于分配角色仆潮,分配權限)
6.Native
1.native:凡是帶了native關鍵字的宏蛉,說明如果Java的作用范圍達不到了,會去調用底層C語言的庫性置!
2.進入本地方法棧
3.調用本地方法本地接口 JNI
4.JNI作用:擴展Java的使用拾并,融合不同的編程語言為java所用!(java誕生的時候C、C++橫行嗅义,想要立足个榕,必須要有調用C、C++的程序)
5.它在內存區(qū)域中專門開辟了一塊標記區(qū)域:Native Method Stack中登記native方法
6.在最終執(zhí)行的時候芥喇,加載本地方法庫中的方法通過JNI
7.PC寄存器(程序計數(shù)器)
每個線程都有一個程序計數(shù)器西采,時線程私有的,就是一個指針继控,指向方法區(qū)中的方法字節(jié)碼
8.方法區(qū)
方法區(qū)是被所有線程共享的械馆,所有字段和方法字節(jié)碼,以及一些特殊方法武通,如構造函數(shù)霹崎,接口代碼也在此定義,簡單說冶忱,所有定義的方法的信息都保存在該區(qū)域尾菇,該區(qū)域屬于共享區(qū)間。
靜態(tài)變量囚枪、常量派诬、類信息(構造方法、接口定義)链沼、運行時常量池存在方法區(qū)中默赂,但是實例變量存在堆內存中,和方法區(qū)無關括勺。
9.棧
- 棧內存缆八,主管程序的運行,生命周期和線程同步
- 線程結束疾捍,棧內存釋放奈辰,對于棧來說邑闺,不存在垃圾回收的問題
- 當前正在執(zhí)行的方法永遠在棧頂驱犹,方法執(zhí)行完了就會被彈出棧
- 棧里存放著:8大基本類型+對象引用+實例的方法
棧運行原理:棧幀
[圖片上傳中...(image.png-72806-1653390101960-0)]
image.png
棧溢出:StackOverflowError
棧+堆+方法區(qū)的交互關系
image.png
10.三種JVM
1.HotSpot
2.BEA JRockit
3.IBM J9 VM
11.堆
一個JVM只有一個堆內存槐壳,堆內存的大小是可以調節(jié)的你雌。
堆內存中還要細分為三個區(qū)域:
- 新生區(qū)(伊甸園區(qū))
- 養(yǎng)老區(qū)
- 永久區(qū)
image.png
GC垃圾回收機制主要發(fā)生在伊甸園區(qū)和養(yǎng)老區(qū),假設內存滿了就會報OOM(堆內存滿了)
垃圾回收大致過程:
1.所有的對象在伊甸園區(qū)誕生成長箫柳,之后會經歷一次輕GC
2.幸存下來的對象進入幸存區(qū)
3.當幸存區(qū)滿了之后袖牙,對象轉移到養(yǎng)老區(qū),并進行重GC
在JDK8以后续滋,永久存儲區(qū)改為元空間
12.新生區(qū),老年區(qū)孵奶、永久區(qū)
12.1新生區(qū)
-類誕生和成長的地方
-伊甸園疲酌,所有的對象都是在伊甸園中new出來的
-幸存區(qū)(0,1)
真理:經過研究,99%的對象都是臨時對象
12.3永久區(qū)
這個區(qū)域是常駐內存的,用來存放JDK攜帶的Class對象朗恳,Interface元數(shù)據湿颅,存儲的是Java運行時的一些環(huán)節(jié)或類信息,這個區(qū)域不存在垃圾回收粥诫,關閉虛擬機就會釋放這個區(qū)域的內存油航。
- jdk1.6之前:永久代,常量池在方法區(qū)中
- jdk1.7:永久代怀浆,但是慢慢退化了谊囚,去永久代,常量池在堆中
-
jdk1.8之后:無永久代执赡,常量池在元空間
image.png
注:這里的云空間只是邏輯上的存在镰踏,物理是不存在
image.png
13.堆內存調優(yōu)
OOM:
1.嘗試擴大堆內存看結果(-Xms1024m -Xmx1024m -XX:+PrintGCDetails)
2.分析內存,看一下那個地方出現(xiàn)了問題(MAT沙合,Jprofiler)
package com.jvm;
import java.util.Random;
/**
* @author:wangjie
* @create:2022-05-25 18:15
* @Description:模擬堆滿了java.lang.OutOfMemoryError: Java heap space
*/
public class OOM {
// -Xms8m -Xmx8m -XX:+PrintGCDetails 設置運行時初始內存分配大小默認1/64奠伪,最大分配內存大小1/4,打印GC垃圾回收機制詳細信息
//-Xms8m -Xmx8m -XX:+HeadDumpOnOutOfMemoryError 如果發(fā)生OutOfMemoryError錯誤就將信息dump下來分析
public static void main(String[] args) {
String str = "wangjie";
while (true){
str+=str+new Random().nextInt(1111111111)+new Random(222222222);
}
}
}
14.GC(垃圾回收機制)
JVM在進行GC時首懈,并不是對這三個區(qū)域統(tǒng)一回收绊率,大部分時候,回收都是新生代究履。
- 新生代
- 幸存區(qū)(from,to)
- 老年區(qū)
GC兩種類:輕GC即舌、重GC
GC題目: - JVM的內存模型和分區(qū) 詳細到每個區(qū)放什么?
- 堆里面的分區(qū)有哪些挎袜?Eden顽聂、from、to盯仪,老年區(qū)紊搪,說說他們的特點
- GC的算法有哪些?標記清除法全景、標記壓縮耀石、復制算法、引用計數(shù)器
14.1常用算法
14.1.1引用計數(shù)法
14.2復制算法
- 好處:沒有多余的內存碎片
- 壞處:浪費了一個內存空間(to區(qū)總是空的)
復制算法最佳使用場景:對象存活時間較低
14.3標記清除法
- 好處:不需要額外空間
- 壞處:兩次掃描爸黄,嚴重浪費時間滞伟,會產生內存碎片
標記清除壓縮算法
image.png
image.png
image.png
15.JMM
Java 內存模型
作用:緩沖一致性協(xié)議,用于定義數(shù)據讀寫的規(guī)則
JVM定義了線程工作內存和主內存之間的抽象關系:線程之間的共享變量存儲在主內存中炕贵,每個線程都有一個私有的本地內存梆奈。
解決共享對象可見性:validate
16.對象創(chuàng)建過程
1.類加載檢查
檢查這條new指令的參數(shù)是否能在常量池中定位到這個類的符號引用,并且檢查這個符號引用代表的類是否被加載過称开、解析亩钟、和初始化過乓梨,如果沒有,就要先執(zhí)行類加載過程清酥。
2.分配內存
在類加載檢查通過之后扶镀,虛擬機為新生對象分配內存,分配內存的方式有兩種焰轻,指針碰撞(規(guī)整情況)和空閑列表(不規(guī)整情況)臭觉,選擇那種分配方式由java堆的內存是否規(guī)整決定,而java堆是否規(guī)整又由垃圾回收算法決定辱志。
3.初始化零值
內存分配完成后蝠筑,虛擬機需要將分配到的內存空間都初始化為零值(不包括對象頭),這一步操作保證了對象的實例字段在 Java 代碼中可以不賦初始值就直接使用荸频,程序能訪問到這些字段的數(shù)據類型所對應的零值菱肖。
4.設置對象頭
初始化零值完成之后,虛擬機要對對象進行必要的設置旭从,例如這個對象是哪個類的實例稳强、如何才能找到類的元數(shù)據信息、對象的哈希碼和悦、對象的 GC 分代年齡等信息退疫。 這些信息存放在對象頭中。 另外鸽素,根據虛擬機當前運行狀態(tài)的不同褒繁,如是否啟用偏向鎖等,對象頭會有不同的設置方式馍忽。
5.執(zhí)行init方法
在上面工作都完成之后棒坏,從虛擬機的視角來看,一個新的對象已經產生了遭笋,但從 Java 程序的視角來看坝冕,對象創(chuàng)建才剛開始,<init> 方法還沒有執(zhí)行瓦呼,所有的字段都還為零喂窟。所以一般來說,執(zhí)行 new 指令之后會接著執(zhí)行 <init> 方法央串,把對象按照程序員的意愿進行初始化磨澡,這樣一個真正可用的對象才算完全產生出來。