[4]-虛擬機垃圾回收

雙親委派機制

  • 類加載器:引導、拓展、系統
  • 獲取系統類加載器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應提供相應的操作去除引用

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章