作爲學習JVM的一個小結,肯定還有很多錯誤,還請多多指正
java中的內存分爲四種:
堆:線程共享,堆中存放是對象,所有的運行時對象存放在堆中;
桟:java中桟的單位是桟幀,線程私有的,每個被調用的方法都會創建一個桟幀用以存放方法的局部變量,操作數桟,動態鏈表,方法出口等等,可分爲爲java方法服務的java方法桟和爲本地方法服務的本地方法桟;
程序計數器:線程私有,相當於字節碼行號指示器,用於指示需要執行的下一條指令。
方法區:線程共享,存放加載後的類信息,常量,靜態變量,以及即時編譯器JIN編譯後的代碼。
常量池:存放類中的常量,基本類型的常量和引用類型的常量(final),字符串常量以及一些以文本形式出現的符號引用;
類加載機制:
類加載過程:
加載:通過一個類的全限定名找到對應的class文件,加載進內存,並創建對應的Class對象;
驗證:檢查 class文件是否符合當前jvm的要求;
準備:爲類變量分配內存,並初始化爲默認的零值;如果類變量被final修飾,則初始化爲當前值;
解析:將常量池中的符號引用替換爲直接引用。
初始化:運行代碼中的賦值語句與靜態塊。
類加載器:
BootstrapClassLoader:啓動類加載器,由c++實現,jvm自身的一部分,負責加載jre/lib/下面的標準類;
ExtClassLoader:擴展類加載器,由java 語言實現,負責加載 jre/ext/下面的標準類;
AppClassLoader:系統類加載器,由java 語言實現,負責加載classpath路徑下的類;
雙親委派模式:
- 即如果加載器遇到一個加載某類的請求,會將此請求委託給它的父類進行加載,如果父類不能加載再自己加載。
- 好處: 避免重複加載,核心API類型不會隨意更改。
GC
判斷對象是否存活,有兩種算法:
引用計數法:
每當一個對象被引用,就將此對象的計數器+1,引用失效計數器-1,如果引用計數器爲零則對象可被回收。很難解決相互引用的問題。可達性分析發(根搜索算法):
通過一系列稱作“GC ROOTS”的對象作爲起始點,將所有的對象看作節點,如果一個對象持有另一個對象的引用,就代表一個對象到另一個對象可達,從GC ROOTS開始遍歷,沒有被遍歷到的對象代表可被回收。- 可作爲GC ROOTS的對象:
- 桟中方法變量的引用對象,
- 方法區中類變量的引用對象,
- 方法區中常量引用的對象,
- 本地方法桟中JNI引用對象。
GC算法
標記-清除算法:
- 標記存活對象,清除其餘對象;容易產生內存碎片。
- 壞處:降低內存使用率。複製算法:
- 每次使用一般=半內存空間,回收時將存活對象複製到另一半內存空間。
- 好處:克服標記-清除算法產生內存碎片的問題;
- 壞處:並不適合存活對象較多的場合,如老年代,浪費內存空間。標記-壓縮算法:
- 標記存活對象,回收時,將將存活對象壓縮到一邊,清除邊界外的區域。
- 好處:克服了複製算法的空間浪費的問題。
- 壞處:適合存活對象較多的場景,如老年代。分代回收算法:
- 根據對象的生存週期分爲新生代與老年代。根據不同的代選取不同的算法,新生代使用複製算法,因爲對象朝生暮死,複製對象效率高,工作量也小;老年代使用標記-壓縮或者標記-清除算法。
收集器:
serial:串行收集器:新生代使用複製算法,老年代使用標記壓縮算法。
parNew:並行收集器:新生代使用多線程,複製算法,老年代依舊使用單線程標記壓縮算法。
parallel:新生代使用複製算法,老年代使用標記壓縮算法。同時讓新生代和老年代都並行收集。可以控制停頓時間以及吞吐量。
cms:併發標記清除收集器,新生代使用複製算法,老年代使用標記清除算法,由於沒有對對象的移動,清除階段可以同用戶線程共同運行。
- 初始標記:標記 可達對象;單獨,短暫停頓。
- 併發標記:標記所有對象;與用戶線程一起,沒有停頓。
- 重新標記:標記在併發階段用戶線程新產生的對象。單獨,短暫停頓。
- 併發清除:基於標記結果直接清除對象,與用戶線程一起,沒有停頓。
- 併發重置:爲下一次GC做準備。- 特點:與用戶線程同時運行,導致GC階段,系統效率下降。
清理不徹底。
- 特點:與用戶線程同時運行,導致GC階段,系統效率下降。