雙親委派機制
- 類加載器:引導、拓展、系統
- 獲取系統類加載器ClassLoader.getSystemClassLoader()
- 實現自己的類加載器,繼承java.lang.ClassLoader,該類加載的父類是該類的類加載器
- 類都維護着一個指向定義該類的類加載器的引用,getClassLoader()
- loadClass():封裝了代理模式,檢查類是否已被加載,調用父類的loadClass(),父類無法加載,調用findClass(),只重寫findClass不會破壞雙親委派,要重寫loadClass()
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException {
synchronized (getClassLoadingLock(name)) {
Class<?> c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
if (parent != null) {
c = parent.loadClass(name, false);
}
else {
c = findBootstrapClassOrNull(name);
}
}
catch (ClassNotFoundException e) {
}
if (c == null) {
long t1 = System.nanoTime();
c = findClass(name);
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
類的生命週期
- 1)加載:由全限定名查找class文件,轉爲方法區運行時數據結構,生成Class對象
- 2)鏈接:校驗、準備(靜態變量初始化)、解析(字段方法名 符號引轉直引)
- 3)初始化(主引):new、反射、main()、static()、static變量get/set、子類即父類
- 4) 卸載:方法區清空類信息,堆中無類的實例、ClassLoader已回收、Class對象無法被引用、反射
類的初始化順序
- 父類的靜態成員、 父類的靜態初始化語句
- 子類的靜態成員、 子類的靜態初始化語句
- 父類的成員、父類的初始化語句、父類的構造函數
- 子類的成員、子類的初始化語句、子類的構造函數
6大區域+直接內存
- 1)程序計數器:各線程記錄下一條字節碼指令
- 2)java棧:各線程每運行一個方法,創建一個棧幀
- 3)本地方法棧
- 1)方法區:類結構信息
- 2)運行時常量池:每個calss文件的常量表
- 3)堆
- 年輕代:複製清理CC
- 老年代:標記整理MM
- 永久代:
內存區域參數
- 堆初始值=Xms;堆最大值=Xmx
- 新生代大小=Xmn;每個線程棧大小=Xss
- 新生代比值=XX:SurvivorRatio Eden:Survivor 8:1:1
- 永久代初始值=XX:PermSize;永久代最大值:XX:MaxPermSize
- 直接升老年代的對象大小=XX:PretenureSizeThreshold
垃圾回收
- 1)對誰進行GC:堆和方法區的內存
- 2)何時進行GC:從root搜索不可到達的對象,且經過第一次標記、清理後,仍然沒有復活的對象
- 3)判斷對象存活:引用計數算法、根搜索算法 (可達性分析算法)
- gc roots: (虛擬機棧、本地方法棧、方法區的類靜態屬性、常量)引用的對象
- 4)GC有環怎麼辦:引用計數算法對此不適用,但是可達性分析算法適用
- 5)如何逃脫GC:重寫finalize(),逃脫一次。沒有重寫或已調用,則無效
- 6)永久代如何GC:永久代和老年代的垃圾回收是綁定的,其中一個佔滿,兩個區都進行垃圾回收
- 7)新生代gc、檢查老年代是否引用新生代的對象:
- 老年代中維護一個512 byte的塊”card table”,所有老年代對象引用新生代對象的記錄
內存泄漏:對象是可達的、對象是無用的
- 例子:vector.add(obj);obj=null;
- 性能調優:線程池和JVM啓動參數
- 現象:GC進行時間變長、full GC次數變多、老年代內存變大
- DUMP定位:jmap:內存:棧快照:二進制;jstack:CPU:線程位置:文本
- 一塊內存、符合垃圾收集器進行收集的標準
- 對象賦予了null,並再也沒調用過該對象
- 對象已賦予了新值,即重新分配了內存空間
引起內存泄漏的幾個原因:
- 1)static集合類,Vector、HashMap等,靜態遍歷的生命週期與應用程序一致
2)監聽器,addListener(),但是釋放對象的時候沒有刪除這些監聽器
3)物理連接,如數據庫連接、網絡連接,獨立於JVM,需顯示關閉
- DataSource.getConnection()創建,close(),自動Resultset 和Statement對象爲NULL
- 連接池,close(),需要顯式地關閉Resultset、Statement 對象其中一個
- 4)內部類、外部模塊的引用
- 模塊B調用了模塊A的一個方法,傳入了一個對象給模塊A,
- 模塊A保持了對該對象的引用,模塊A應提供相應的操作去除引用