一.JVM概述
1.JVM的作用
?把字節碼編譯為機器碼去執行,負責把字節碼裝載到虛擬機中

2.JVM的組成部分
- 類加載器(ClassLoader)
- 運行時數據區(Runtime Data Area)
- 本地方法庫(Execution Engine)
- 執行引擎(Native Interface)
程序在執行過程中需要把java文件轉換為字節碼文件,然后通過類加載器將文件存儲在內存中的運行時數據區,而字節碼文件是JVM的一套指令集規范,并不能直接交給底層系統去執行,因此需要特定命令的解析器執行引擎,將字節碼編譯為底層系統指令載交給cpu去執行,而這個過程中需要調用本地方法接口去實現整個程序的功能.
二.JVM類加載
1.類加載概述
類加載子系統負責從文件系統或網絡中加載字節碼文件,它只負責加載字節碼文件,至于可不可以運行,則有執行引擎決定
2.類加載過程
2.1加載
使用流將硬盤上的字節碼文件加載到內存中的運行時數據區的方法區,并生成對象的class對象
2.2鏈接
鏈接又分為三個步驟:
-驗證:驗證字節碼格式是否正確,對字節碼描述的信息進行語義分析,以保證其描述的信息符合java的語言規范
-準備:為類中的靜態屬性進行賦值(賦的值為0,在初始化階段在進行賦值)
? ? static int a=123; ? 準備階段a的值為0,在初始化階段才賦值為123
-解析:將字節碼中的邏輯引用替換為直接引用
邏輯引用:字節碼中的邏輯符號
符號引用:內存地址
2.3初始化
為類的靜態變量進行正確的賦值
類什么時候會初始化?
類只要被用到了都會被加載
1.new對象
2.加載子類時
3.反射機制
4.運行類中的main方法
5.使用了類的靜態成員(類.靜態變量? 類.靜態方法)
類什么時候不會被加載?
1.只訪問了類的靜態常量
2.創建的數組對象,只是作為類型存在
3.類加載器的分類
在jvm角度來說,應該被分為倆類:
1.引導類加載器,使用 C/C++語言實現,嵌套在 JVM 內部.它用來加載 java 核心類庫.
2.其他所有類加載器,這些類加載器全部由java語言實現,獨立存在于jvm外部,并且全部繼承自抽象類 java.lang.ClassLoader
站在java程序員的角度應該被分為三類:
1.引導類加載器
2.擴展類加載器,從 java.ext.dirs 系統屬性所指定的目錄中加載類庫,或從 JDK 系統安裝目錄jre/lib/ext 子目錄(擴展目錄)下加載類庫
3.應用程序類加載器,加載我們自己定義的類,用于加載用戶類路徑(classpath)上所有的類
4.雙親委派機制
java虛擬機對class文件采用的是按需加載的方式,也就是需要用到類時才把他的class文件加載到內存中生成class對象,在加載某個類的字節碼文件時,jvm采用了雙親委派機制,即把請求交給父類處理,是一種任務委派機制.
工作原理:
如果一個類加載器收到了類加載請求,這個類加載器并不會自己先加載,而是將請求委托給父類的加載器去執行,如果父類加載器還存在父類,則繼續向上委托,一次遞歸,直至得到頂層的啟動類加載器,如果父類的加載器可以完成加載任務就成功返回,然后無法完成,子類才會自己嘗試加載,如果均加載失敗,就會拋出 ClassNotFoundException 異常
優點:安全,可以避免自己寫的類替換java的核心類
如何打破雙親委派機制?
可以自定義類加載器
在 ClassLoader 類中涉及類加載的方法有兩個,loadClass(String name), findClass(String name),這兩個方法并沒有被 final 修飾,也就表示其他子類可以重寫.
三.運行時數據區
1.運行時數據區組成概述
2.程序計數器
用來記錄下一條指令的地址,也就是即將要執行的指令,由執行引擎執行
特點:
?它是一塊很小的內存區域,也是運行速度最快的存儲區域
?在JVM規范中,每個線程都有一個計數器,是線程私有的,他的生命周期與線程一致?會記錄當前線程正在執行的java程序的JVM指令地址?是唯一一個JVM規范中沒有規定任何OutOfMemoryError情況的區域
3.虛擬機棧

4.堆
4.1堆內存的劃分
在JDK1.8被分為新生代和老年代,新生代又被分為伊甸園區和幸存者區
為什么分區(分代)?
根據對象的存活概率進行分區,將存活時間長的放到老年代,減少掃描垃圾的時間和GC頻率,針對分類進行不同的垃圾回收算法,對算法揚長避短。
對象創建內存分配過程
將剛創建的新對象放到伊甸園區,當垃圾回收時將幸存下來的對象放到幸存者0區,再次進行垃圾回收時,將幸存者0區和伊甸園區的對象放到幸存者1中,每次保證有一個幸存者區是空閑的.當一個對象經歷15次垃圾回收(被回收對象默認次數是15,可以通過-XX:MaxTenuringThreshold=<N>設置次數)時依然存活,會被放入老年區,或者如果一個對象比較的,也可以直接存放到老年區中.在老年代,相對悠閑,當老年代內存不足時,觸發 GC,進行老年代的內存清理.?若老年代執行了 GC 之后發現依然無法進行對象存儲,會對整堆進行 GC, 之后依然無法進行對象存儲, 就會產生 OOM 異常. Java.lang.OutOfMemoryError:Java heap space
為什么是15次?
在對象頭中,它由4位數據去對GC年齡進行記錄保存,最大為1111,即15
5.方法區
一個被線程共享的區域,主要存儲加載的類字節碼、class/method/field 等元數據、static final 常量、static 變量、即時編譯器編譯后的代碼等數據。在物理上與堆是屬于同一個空間,但在邏輯上對其進行區分,被稱為元空間
6.本地方法棧
? Java 虛擬機棧管理 java 方法的調用,而本地方法棧用于管理本地方法的調用.? 本地方法棧也是線程私有的.? 允許被實現成固定或者是可動態擴展的內存大小.內存溢出方面也是相同的. 如果線程請求分配的棧容量超過本地方法棧允許的最大容量拋出StackOverflowError.? 本地方法是用 C 語言寫的.? 它的具體做法是在 Native Method Stack 中登記 native 方法,在 Execution Engine 執行時加載本地方法庫.
四.本地方法接口
1.什么是本地方法?
簡單來說,被native修飾的方法就是本地方法,該類方法底層不是由java語言編寫,例如c
2.為什么使用本地方法?
與java環境外交互,與硬件設備交互,java屬于應用程序語言,沒有與硬件設備直接交互的權限
五.執行引擎
將字節碼解釋/編譯為對應平臺上的本地機器指令
什么是解釋器和編譯器?
解釋執行雖然效率低,但是在程序開始執行后可以立即投入使用,編譯執行雖然將一些熱點代碼編譯后緩存起來,執行效率高,但是需要花費一定時間,所以就采用開始時使用解釋器執行,等編譯器編譯完成后就采用編譯執行
六.垃圾回收機制
1.垃圾回收概述
1.1什么是垃圾?
垃圾是指沒有被任何引用指向的對象,這個對象就是需要被回收的垃圾.
如果垃圾長時間不回收,這些垃圾對象會一直占用內存空間,導致空間無法被其他對象所使用,直到應用程序關閉,甚至導致內存溢出.
1.2垃圾回收概述
早期的 C/C++時代,垃圾回收基本上是手工進行的,開發人員可以使用 new 關鍵字進行內存申請,并使用 delete 關鍵字進行內存釋放。這種方式可以靈活控制內存釋放的時間,但是會給開發人員帶來頻繁申請和釋放內存的管理負擔。倘若有一處內存區間由于程序員編碼的問題忘記被回收,那么 就會產生內存泄漏,垃圾對象永遠無法被清除,隨著系統運行時間的不斷增長,垃圾對象所耗內存可能持續上升,直到出現內存溢出并造成應用程序崩潰。

2.垃圾回收的相關算法
2.1垃圾回收標記階段算法
可達性分析算法是以根(GCRoots)為起始點,按照從上至下的方式搜索被根對象所連接的目標對象是否可達。使用可達性分析算法后,內存中的存活對象都會被根直接或間接連接著,搜索所走過的路徑稱為引用鏈(Reference Chain)如果目標對象沒有任何引用鏈相連,則是不可達的,就意味著該對象己經死亡,可以標記為垃圾對象。
哪些對象可以稱為活躍對象(GCroots)?
1.虛擬機棧中引用的對象
2.方法區中類靜態屬性引用的對象
3.所有同步鎖synchronized持有的對象
4.java虛擬機內部的引用
基本數據類型對應的class對象,一些常駐的異常對象(nullpointerexception,outofmemoryerror),系統類加載器
2.2垃圾回收階段算法


3.垃圾回收器
按線程數可以分為 單線程(串行) 垃圾回收器和 多線程(并行) 垃圾回收器按照工作模式分,可以分為 獨占式 和 并發式 垃圾回收器。按工作的內存區間分,又可分為 年輕代垃圾回收器 和 老年代垃圾回收器。
3.3CMS回收器
垃圾回收過程初始標記:Stop The World,僅使用一條初始標記線程對所有與 GC Roots 直接關聯的對象進行標記。并發標記:垃圾回收線程,與用戶線程并發執行。此過程進行可達性分析,標記出所有廢棄對象。重新標記:Stop The World,使用多條標記線程并發執行,將剛才并發標記過程中新出現的廢棄對象標記出來。并發清除:只使用一條 GC 線程,與用戶線程并發執行,清除剛才標記的對象。這個過程非常耗時。并發標記與并發清除過程耗時最長,且可以與用戶線程一起工作,因此,總體上說,CMS 收集器的內存回收過程是與用戶線程一起并發執行的。
3.4G1回收器

① 初始標記:標記出 GC Roots 直接關聯的對象,這個階段速度較快,需要停止用戶線程,單線程執行。② 并發標記:從 GC Root 開始對堆中的對象進行可達新分析,找出存活對象,這個階段耗時較長,但可以和用戶線程并發執行。③ 最終標記:修正在并發標記階段引用戶程序執行而產生變動的標記記錄。④ 篩選回收:篩選回收階段會對各個 Region 的回收價值和成本進行排序,根據用戶所期望的 GC 停頓時間來指定回收計劃(用最少的時間來回收包含垃圾最多的區域.這就是 Garbage First 的由來——第一時間清理垃圾最多的區塊),這里為了提高回收效率,并沒有采用和用戶線程并發執行的方式,而是停頓用戶線程。適用場景:要求盡可能可控 GC 停頓時間;內存占用較大的應用。
?