天天看點

JVM記憶體區域解析

“原創精選,轉載注明出處,三克油”

@Date 2017.05.24

概念介紹(基于JDK7)
  • 堆(分代收集算法)
    1. 年輕代(Minor GC)
      • Eden區
        • 存儲新對象或者生命周期很短的對象
      • From Survivor區
        • Eden區的垃圾回收仍能存活下來的依舊存在引用的對象會待在這個區域
      • To Survivor區
    2. 年老代
      • Eden區和Survivor區的多次GC後仍然存活下來的對象 - major GC
      • 記憶體大小為-Xmx對應的值減去-Xmn對應的值
      • 建立的對象也有可能直接進入老年代
        1. 大對象:可通過啟動參數設定-XX:PretenureSizeThreshold超過則直接在老年代配置設定
        2. 大的數組對象,且數組中無引用外部對象
  • 方法區(Non-Heap(非堆))
    1. 永久代(HotSpot VM)
      • 各個線程共享的記憶體區域
      • 方法區是線程安全的
      • 存儲已被虛拟機加載的類資訊、方法(資料及代碼)、常量、靜态變量、即時編譯器編譯後的代碼等資料
      • 在Java8裡已被廢除了,被元空間取代
    2. 運作時常量池(Runtime Constant Pool)
      • 存放編譯期生成的各種字面量和符号引用
      • 運作期間也可能将新的常量放入池中
      • String類的intern()方法
    1. 虛拟機棧
      • 方法執行的記憶體模型
      • 每個線程都有自己專屬的棧,這個棧是别的線程無法通路的
      • 生命周期與線程相同
      • 存儲局部變量表(存放方法參數和方法内部定義的局部變量)、操作棧、動态連結、方法出口、方法調用的中間結果及傳回位址
      • 線程請求的棧深度大于虛拟機所允許的深度,将抛出StackOverflowError異常
      • 虛拟機棧可動态擴充,當擴充時無法申請到足夠的記憶體時會抛出OutOfMemoryError異常
    2. 本地方法棧
      • 為虛拟機使用到的Native方法服務
  • 計數器
    1. 程式計數器
      • 分支、循環、跳轉、異常處理、線程恢複
      • 每條線程都需要有一個獨立的程式計數器
      • JVM執行的位元組碼指令位址
      • 目前線程所執行的位元組碼的行号訓示器
      • 位元組碼解釋器工作時就是通過改變這個計數器的值來選取下一條需要執行的位元組碼指令
      • 此記憶體區域是唯一一個在Java 虛拟機規範中沒有規定任何OutOfMemoryError情況的區域
  • 直接記憶體(Direct Memory)
    1. NIO出現後使用
      • 本機直接記憶體的配置設定不會受到Java堆大小的限制
持久代 --> 元空間 (JDK8)
  • 元空間
    1. 本地堆記憶體中的一部分
    2. 達到最大門檻值時進行該區域清理
    3. 類及相關的中繼資料的生命周期與類加載器的一緻
    4. 使用-XX:MaxMetaspaceSize參數可以設定元空間的最大值
    5. 預設是沒有上限的,系統記憶體上限是多少它就是多少
    6. 達到設定的最大值後,對于無用的類和類加載器,垃圾收集此時會觸發
Error
  • 記憶體溢出(Out Of Memory) : 程式在申請記憶體時,沒有足夠的記憶體空間供其使用
  • 記憶體洩露(Memory Leak) : 程式在申請記憶體後,無法釋放已申請的記憶體空間.一次記憶體洩露可以忽略,洩露堆積後果很嚴重,最終會導緻Out Of Memory.