JVM學習筆記
學習方式:
1.百度
2.思維導圖
請你談談對JVM的理解? ?java8虛擬機和之前的變化更新?
什么是OOM,實名是棧溢出StackOverFlowError?怎么分析?
JVM的常用調優(yōu)參數有哪些?
內存快照如何抓取,怎么分析Dump文件?知道嗎?
談談JVM中,類加載器你的認識?
1.JVM的位置

2.JVM的體系結構

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

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

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

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

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