JVM學(xué)習(xí)筆記
學(xué)習(xí)方式:
1.百度
2.思維導(dǎo)圖
請你談?wù)剬?duì)JVM的理解? ?java8虛擬機(jī)和之前的變化更新?
什么是OOM,實(shí)名是棧溢出StackOverFlowError?怎么分析?
JVM的常用調(diào)優(yōu)參數(shù)有哪些?
內(nèi)存快照如何抓取,怎么分析Dump文件?知道嗎?
談?wù)凧VM中,類加載器你的認(rèn)識(shí)?
1.JVM的位置

2.JVM的體系結(jié)構(gòu)

3.類加載器
作用:加載 Class 文件 ?new Student();
1.虛擬機(jī)自帶的加載器
2.啟動(dòng)類(根)加載器
3.擴(kuò)展類加載器
4.應(yīng)用程序加載器
4.雙親委派機(jī)制
1.類加載器收到類加載的請求
2.將這個(gè)請求委托給父類加載器去完成,一直向上委托,直到啟動(dòng)類加載器
3.啟動(dòng)加載器檢查是否能夠加載當(dāng)前這個(gè)類,能加載就結(jié)束,否則,拋出異常,通知子類加載器進(jìn)行加載
4.重復(fù)步驟3
5.沙箱安全機(jī)制
Java安全模型的核心就是Java沙箱(sandbox),什么是沙箱?沙箱是一個(gè)限制程序運(yùn)行的環(huán)境。沙箱機(jī)制就是將 Java 代碼限定在虛擬機(jī)(JVM)特定的運(yùn)行范圍中,并且嚴(yán)格限制代碼對(duì)本地系統(tǒng)資源訪問,通過這樣的措施來保證對(duì)代碼的有效隔離,防止對(duì)本地系統(tǒng)造成破壞。沙箱主要限制系統(tǒng)資源訪問,那系統(tǒng)資源包括什么?——CPU、內(nèi)存、文件系統(tǒng)、網(wǎng)絡(luò)
。不同級(jí)別的沙箱對(duì)這些資源訪問的限制也可以不一樣。
??所有的Java程序運(yùn)行都可以指定沙箱,可以定制安全策略。
java中的安全模型:
??在Java中將執(zhí)行程序分成本地代碼和遠(yuǎn)程代碼兩種,本地代碼默認(rèn)視為可信任的,而遠(yuǎn)程代碼則被看作是不受信的。對(duì)于授信的本地代碼,可以訪問一切本地資源。而對(duì)于非授信的遠(yuǎn)程代碼在早期的Java實(shí)現(xiàn)中,安全依賴于沙箱 (Sandbox) 機(jī)制。如下圖所示 JDK1.0安全模型

但如此嚴(yán)格的安全機(jī)制也給程序的功能擴(kuò)展帶來障礙,比如當(dāng)用戶希望遠(yuǎn)程代碼訪問本地系統(tǒng)的文件時(shí)候,就無法實(shí)現(xiàn)。因此在后續(xù)的 Java1.1 版本中,針對(duì)安全機(jī)制做了改進(jìn),增加了安全策略
,允許用戶指定代碼對(duì)本地資源的訪問權(quán)限。如下圖所示 JDK1.1安全模型

??在 Java1.2 版本中,再次改進(jìn)了安全機(jī)制,增加了代碼簽名
。不論本地代碼或是遠(yuǎn)程代碼,都會(huì)按照用戶的安全策略設(shè)定,由類加載器加載到虛擬機(jī)中權(quán)限不同的運(yùn)行空間,來實(shí)現(xiàn)差異化的代碼執(zhí)行權(quán)限控制。如下圖所示 JDK1.2安全模型

??當(dāng)前最新的安全機(jī)制實(shí)現(xiàn),則引入了域 (Domain) 的概念。虛擬機(jī)會(huì)把所有代碼加載到不同的系統(tǒng)域和應(yīng)用域,系統(tǒng)域部分專門負(fù)責(zé)與關(guān)鍵資源進(jìn)行交互,而各個(gè)應(yīng)用域部分則通過系統(tǒng)域的部分代理來對(duì)各種需要的資源進(jìn)行訪問。虛擬機(jī)中不同的受保護(hù)域 (Protected Domain),對(duì)應(yīng)不一樣的權(quán)限 (Permission)。存在于不同域中的類文件就具有了當(dāng)前域的全部權(quán)限,如下圖所示 最新的安全模型(jdk 1.6)

??以上提到的都是基本的Java 安全模型概念
,在應(yīng)用開發(fā)中還有一些關(guān)于安全的復(fù)雜用法
,其中最常用到的 API 就是 doPrivileged。doPrivileged 方法能夠使一段受信任代碼獲得更大的權(quán)限,甚至比調(diào)用它的應(yīng)用程序還要多,可做到臨時(shí)訪問更多的資源
。有時(shí)候這是非常必要的,可以應(yīng)付一些特殊的應(yīng)用場景。例如,應(yīng)用程序可能無法直接訪問某些系統(tǒng)資源,但這樣的應(yīng)用程序必須得到這些資源才能夠完成功能。
組成沙箱的基本組件:
字節(jié)碼校驗(yàn)器
(bytecode verifier):確保Java類文件遵循Java語言規(guī)范。這樣可以幫助Java程序?qū)崿F(xiàn)內(nèi)存保護(hù)。但并不是所有的類文件都會(huì)經(jīng)過字節(jié)碼校驗(yàn),比如核心類。- 類裝載器
(class loader):其中類裝載器在3個(gè)方面對(duì)Java沙箱起作用
它防止惡意代碼去干涉善意的代碼;
它守護(hù)了被信任的類庫邊界;
它將代碼歸入保護(hù)域,確定了代碼可以進(jìn)行哪些操作。
??虛擬機(jī)為不同的類加載器載入的類提供不同的命名空間,命名空間由一系列唯一的名稱組成,每一個(gè)被裝載的類將有一個(gè)名字,這個(gè)命名空間是由Java虛擬機(jī)為每一個(gè)類裝載器維護(hù)的,它們互相之間甚至不可見。
??類裝載器采用的機(jī)制是雙親委派模式。
從最內(nèi)層JVM自帶類加載器開始加載,外層惡意同名類得不到加載從而無法使用;
由于嚴(yán)格通過包來區(qū)分了訪問域,外層惡意的類通過內(nèi)置代碼也無法獲得權(quán)限訪問到內(nèi)層類,破壞代碼就自然無法生效。
存取控制器
(access controller):存取控制器可以控制核心API對(duì)操作系統(tǒng)的存取權(quán)限,而這個(gè)控制的策略設(shè)定,可以由用戶指定。安全管理器
(security manager):是核心API和操作系統(tǒng)之間的主要接口。實(shí)現(xiàn)權(quán)限控制,比存取控制器優(yōu)先級(jí)高。- 安全軟件包
(security package):java.security下的類和擴(kuò)展包下的類,允許用戶為自己的應(yīng)用增加新的安全特性,包括:
安全提供者
消息摘要
數(shù)字簽名 ?keytools
加密
鑒別
6.Native
凡是帶了 native 關(guān)鍵字的,說明java的作用范圍打不到了,會(huì)去調(diào)用底層c語言的庫
調(diào)用本地方法接口 JNI
JNI 作用:擴(kuò)展 java 的使用,融合不同的編程語言為 java 所用
java誕生的時(shí)候 c、c++橫行,想要立足,必須要有調(diào)用c、c++ 的程序
它在內(nèi)存區(qū)域中專門開辟了一塊標(biāo)記區(qū)域:Native Method Stack ,登記 native 方法
在最終執(zhí)行的時(shí)候,加載本地方法庫中的方法通過JNI
使用場景:java程序驅(qū)動(dòng)打印機(jī)、管理系統(tǒng),Robot()掌握即可,在企業(yè)家應(yīng)用中較為少見
現(xiàn)在寫得少了,多用調(diào)用其他接口: ? ?Socket. . WebService~. .http~
7.PC寄存器
程序計(jì)數(shù)器: Program Counter Register
每個(gè)線程都有一個(gè)程序計(jì)數(shù)器,是線程私有的,就是一個(gè)指針, 指向方法區(qū)中的方法字節(jié)碼(用來存儲(chǔ)指向像 一條指令的地址, 也即將要執(zhí)行的指令代碼) , 在執(zhí)行引擎讀取下一條指令,是一-個(gè)非常小的內(nèi)存空間,幾乎可以 忽略不計(jì)
8.方法區(qū)
Method Area方法區(qū)
方法區(qū)是被所有線程共享,所有字段和方法字節(jié)碼,以及一些特殊方法,如構(gòu)造函數(shù),接口代碼也在此定義, 簡單說,所有定義的方法的信息都保存在該區(qū)域,此區(qū)域?qū)儆诠蚕韰^(qū)間;
靜態(tài)變量、常量、類信息(構(gòu)造方法、接口定義)、運(yùn)行時(shí)的常量池存在方法區(qū)中,但是實(shí)例變量存在堆內(nèi)存 中,和方法區(qū)無關(guān)。
static,final,Class,常量池
9.棧
棧:數(shù)據(jù)結(jié)構(gòu)
程序:數(shù)據(jù)結(jié)構(gòu)+算法 ——持續(xù)學(xué)習(xí)
程序:框架+業(yè)務(wù)邏輯 ——吃飯
棧:先進(jìn)后出、后進(jìn)先出
隊(duì)列:先進(jìn)先出( FIFO: First input First Output )
棧:棧內(nèi)存,主管程序的運(yùn)行,生命周期和線程同步;
線程結(jié)束,棧內(nèi)存也就是釋放,對(duì)于棧來說,不存在垃圾回收問題
一旦線程結(jié)束,棧就over
棧里面都有些什么:8大基本類型+對(duì)象引用+實(shí)例的方法
棧運(yùn)行原理:棧幀
棧滿了: StackOverflowError——棧溢出異常
棧+堆+方法區(qū):交互關(guān)系
10.三種JVM
Sun 公司 HotSpot
BEA 公司 Jrockit
IBM 公司 J9VM
我們學(xué)習(xí)的都是 HotSpot
11.堆
Heap,一個(gè)JVM只有一個(gè)內(nèi)存,堆內(nèi)存的大小是可以調(diào)節(jié)的。
類加載器讀取了類文件后,一般會(huì)把什么東西放到堆中?類,方法,常量,變量,保存所有引用類型的真實(shí)對(duì)象
堆內(nèi)存中還要分為三個(gè)區(qū)域:
新生區(qū) ?(伊甸園區(qū))
養(yǎng)老區(qū)
永久區(qū)
GC 垃圾回收,主要是伊甸園區(qū)和養(yǎng)老區(qū)
假設(shè)內(nèi)存滿了,就會(huì)報(bào)OOM,堆內(nèi)存不夠
java.lang.OutOfMemoryError: Java heap space|
在JDK8以后,永久存儲(chǔ)區(qū)改了個(gè)名字(元空間)
12.新生區(qū)、老年區(qū)
新生區(qū)
類:誕生和成長的地方,甚至死亡
伊甸園,所有的對(duì)象都是在伊甸園區(qū) new 出來的
幸存者區(qū) ?(0,1)
老年區(qū)
真理;經(jīng)過研究,99%的對(duì)象都是臨時(shí)對(duì)象
13.永久區(qū)
這個(gè)區(qū)域常駐內(nèi)存的。用啦存放JDK自身攜帶的Class對(duì)象,Interface 元數(shù)據(jù),存儲(chǔ)的是java運(yùn)行時(shí)的一些環(huán)境或類信息,這個(gè)區(qū)域不存在垃圾回收。關(guān)閉VM虛擬機(jī)就會(huì)釋放這個(gè)區(qū)域的內(nèi)存
什么情況下會(huì)出現(xiàn)永久區(qū)崩潰:一個(gè)啟動(dòng)類,加載了大量的第三方j(luò)ar包。Tomcat部署了太多的應(yīng)用。大量動(dòng)態(tài)生成的反射類,不斷被加載。直到內(nèi)存滿,就會(huì)出現(xiàn)OOM。
jdk1.6 之前:永久代,常量池是在方法區(qū)
jdk1.7 : 永久代,誕生慢慢的退化了,去永久代,常量池在堆中
jdk18 ?:無永久代,常量池在元空間
14.堆內(nèi)存調(diào)優(yōu)
-Xms 默認(rèn)為 電腦內(nèi)存的1/64
-Xmx 默認(rèn) 為 電腦內(nèi)存的1/4
-Xms1m ?初始化內(nèi)存大小1m
-Xmx8m 最大分配內(nèi)存
-Xms1m -Xmx8m -XX:+HeapDumpOnOutOfMemoryError
-XX:+HeapDumpOnOutOfMemoryError 如果出現(xiàn)OutOfMemoryError異常就從堆中Dump文件出來
-XX:+printGCDetails 打印GC垃圾回收信息
15.GC —— 常用算法
JVM在進(jìn)行GC時(shí),并不是對(duì) 這三個(gè)區(qū)域統(tǒng)一回收。大部分時(shí)候,回收都是新時(shí)代
新生代
幸存區(qū)(from,to)
老年區(qū)
GC兩種類:清GC(普通的GC),重GC(全局GC)
GC題目 :
JVM的內(nèi)存模型和分區(qū)—詳細(xì)到每個(gè)區(qū)放什么?
堆利姆的分區(qū)有哪些?Eden,from,to,老年區(qū),說說他們的特點(diǎn)
GC的算法有哪些?標(biāo)記清除法,標(biāo)記壓縮,復(fù)制算法,引用計(jì)數(shù)器,怎么用?
輕GC和重GC分別在什么時(shí)候發(fā)生
引用計(jì)數(shù)法
復(fù)制算法
流程:
好處:沒有內(nèi)存的碎片
壞處:浪費(fèi)了內(nèi)存空間:多了一半空間永遠(yuǎn)是空to,假設(shè)對(duì)象100%存活(極端情況)
復(fù)制算法最佳使用場景:對(duì)象存活度較低的情況下
標(biāo)記清除法
優(yōu)點(diǎn):不需要額外的空間
缺點(diǎn):兩次掃描,嚴(yán)重浪費(fèi)時(shí)間,會(huì)產(chǎn)生內(nèi)存碎片
標(biāo)記壓縮
再優(yōu)化
標(biāo)記清除壓縮
先標(biāo)記清除幾次
再壓縮
總結(jié)
內(nèi)存效率:復(fù)制算法>標(biāo)記清除算法>標(biāo)記壓縮算法(時(shí)間復(fù)雜度)
內(nèi)存整齊度:復(fù)制算法=標(biāo)記壓縮算法>標(biāo)記清除算法
內(nèi)存 利用率:標(biāo)記壓縮算法=標(biāo)記清除算法>復(fù)制算法
思考 問題:難道沒沒有最優(yōu)算法嗎?
答案:沒有,沒有最好的算法,只有最合適的算法 ------> GC :分代手機(jī)算法
年輕代:
存活率低
復(fù)制算法
老年代:
區(qū)域大: 存活率
標(biāo)記清除(內(nèi)存碎片不是太多)+標(biāo)記壓縮混合 ?實(shí)現(xiàn)
16.JMM
1.什么是JMM——java內(nèi)存模型
JMM:Java Memory Model的縮寫
2.它干嘛的? ?官方,其他人的博客,對(duì)應(yīng)的視頻
作用:緩存一致性協(xié)議,用于定義數(shù)據(jù)讀寫規(guī)則(遵守,找到這個(gè)規(guī)則)
JMM定義了線程工作內(nèi)存和主內(nèi)存之間的抽象關(guān)系:線程之間的共享變量存儲(chǔ)在主內(nèi)存(Main Memory)中,每個(gè)線 程都有一個(gè)私有的本地內(nèi)存(Local Memory)
解決共享對(duì)象可見性問題:volilate
3.它該如何學(xué)習(xí)?
JMM:抽象的概念,理論
JMM對(duì)這八種指令的使用,制定了如下規(guī)則:
不允許read和load、store和write操作之一單獨(dú)出現(xiàn)。即使用了read必須load,使用了store必須write
不允許線程丟棄他最近的assign操作,即工作變量的數(shù)據(jù)改變了之后,必須告知主存
不允許一個(gè)線程將沒有assign的數(shù)據(jù)從工作內(nèi)存同步回主內(nèi)存
一個(gè)新的變量必須在主內(nèi)存中誕生,不允許工作內(nèi)存直接使用一個(gè)未被初始化的變量。就是懟變量實(shí)施use、store操作之前,必須經(jīng)過assign和load操作
一個(gè)變量同一時(shí)間只有一個(gè)線程能對(duì)其進(jìn)行l(wèi)ock。多次lock后,必須執(zhí)行相同次數(shù)的unlock才能解鎖
如果對(duì)一個(gè)變量進(jìn)行l(wèi)ock操作,會(huì)清空所有工作內(nèi)存中此變量的值,在執(zhí)行引擎使用這個(gè)變量前,必須重新load或assign操作初始化變量的值
如果一個(gè)變量沒有被lock,就不能對(duì)其進(jìn)行unlock操作。也不能unlock一個(gè)被其他線程鎖住的變量
對(duì)一個(gè)變量進(jìn)行unlock操作之前,必須把此變量同步回主內(nèi)存
JMM對(duì)這八種操作規(guī)則和對(duì)
就能確定哪里操作是線程安全,哪些操作是線程不安全的了。但是這些規(guī)則實(shí)在復(fù)雜,很難在實(shí)踐中直接分析。所以一般我們也不會(huì)通過上述規(guī)則進(jìn)行分析。更多的時(shí)候,使用java的happen-before規(guī)則來進(jìn)行分析。感謝狂神