JVM 堆內存
1. 前言
本節主要講解運行時數據區的堆內存。本節主要知識點如下:
- 掌握堆內存空間結構圖,從總體層面認識堆內存,為本節重點內容之一;
- 了解 JVM 堆空間的基本概念,為本節的基礎知識點;
- 了解堆內存的分代概念,年輕代,eden區,from/to,幸存者及老年代,為本節核心知識點,后續對垃圾回收講解時,大部分的回收都是發生在堆內存中,掌握分代概念是學習垃圾回收機制的必要前提。
2. 堆內存結構
堆內存是運行時數據區中非常重要的結構,實例對象會存放于堆內存中。在后續小節中,我們講解 GC 垃圾回收器,絕大多數的垃圾回收都發生在堆內存中,因此對于 JVM 來說,堆內存占據著十分重要的且不可替代的位置。
我們先來看下堆內存的結構圖,初步了解堆內存的整體內存劃分。
從上圖可以看到如下幾個要點:
- 堆內存從結構上來說分為年輕代(YoungGen)和老年代(OldGen)兩部分;
- 年輕代(YoungGen)又可以分為生成區(Eden)和幸存者區(Survivor)兩部分;
- 幸存者區(Survivor)又可細分為 S0區(from space)和 S1區 (to space)兩部分。
從圖中,我們能夠大體了解堆內存的結構劃分,后文在講解分代概念時,我們會提供更加直觀,更加清晰的內存結構圖。
3. 什么是堆內存
物理層面:從物理層面(硬件層面)來說,當 Java 程序開始運行時,JVM 會從操作系統獲取一些內存。JVM 使用這些內存,這些內存的一部分就是堆內存。
Java層面:從開發層面來說,堆內存通常在存儲地址的底層,向上排列。當一個對象通過 new 關鍵字或通過其他方式創建后,對象從堆中獲得內存。當對象不再使用了,被當做垃圾回收掉后,這些內存又重新回到堆內存中。
總結來說,堆內存是JVM啟動時,從操作系統獲取的一片內存空間,他主要用于存放實例對象本身,創建完成的對象會放置到堆內存中。
4. 堆內存的分代概念
從上文堆內存的結構圖中,我們看到了比較多的JVM堆內存中的專有名詞,比如:年輕代,老年代。那么對于堆內存來說,分代是什么意思呢?為什么要進行分代呢?
分代:將堆內存從概念層面進行模塊劃分,總體分為兩大部分,年輕代和老年代。從物理層面將堆內存進行內存容量劃分,一部分分給年輕代,一部分分給老年代。這就是我們所說的分代。
分代的意義:易于堆內存分類管理,易于垃圾回收。類似于我們經常使用的 Windows 操作系統,我們會將物理磁盤劃出一部分存儲空間作為用戶系統安裝盤(如 C 盤),我們還極大可能將剩余的磁盤空間劃分為 C, D, E 等磁盤,用于存儲同一類型的數據。
-
易于管理:對于堆空間的分代也是如此,比如新創建的對象會進入年輕代(YoungGen)的生成區(Eden),生命周期未結束的且可達的對象,在經歷多次垃圾回收之后,會存放入老年代(OldGen),這就是分類管理;
-
易于垃圾回收:將對象根據存活概率進行分類,對存活時間長的對象,放到固定區,從而減少掃描垃圾時間及 GC 頻率。針對分類進行不同的垃圾回收算法,對算法揚長避短。
Tips:關于上文提到的垃圾回收部分的知識,我們會在后邊的章節做專門的、詳細的講解,此處我們先做了解即可。
5. 堆內存結構詳解
講解完分代的概念,我們來對堆內存中的不同的代,不同的內存空間的作用進行更加詳細的講解。講解之前,我們來看下如下示意圖,更加直觀的了解堆內存結構。
堆內存每個模塊之間的關系及各自的特點概述如下:
- JVM 內存劃分為堆內存和非堆內存,堆內存分為年輕代(YoungGen)、老年代(OldGen);
- 年輕代又分為 Eden 和 Survivor 區。Survivor 區由 FromSpace 和 ToSpace 組成。Eden 區占大容量,Survivor 兩個區占小容量,默認比例是 8:1:1;
- 堆內存存放的是對象,垃圾收集器就是收集這些對象,然后根據 GC 算法回收;
- 新生成的對象首先放到年輕代 Eden 區,當 Eden 空間滿了,觸發 Minor GC,存活下來的對象移動到Survivor0 區,Survivor0 區滿后觸發執行 Minor GC,Survivor0 區存活對象移動到 Suvivor1 區,這樣保證了一段時間內總有一個 survivor 區為空。經過多次 Minor GC 仍然存活的對象移動到老年代;
- 老年代存儲長期存活的對象,GC 期間會停止所有線程等待 GC 完成,所以對響應要求高的應用盡量減少發生 Major GC,避免響應超時。
Tips:關于上文提到的垃圾回收部分的知識,我們會在后邊的章節做專門的、詳細的講解,此處我們主要關注在堆內存的每個模塊的概念,特點及作用。對于垃圾回收部分的知識,我們后續再進行學習。
6. 小結
本節主要講解了運行時數據區里邊的堆內存,堆內存是一塊共享內存區域,在運行時數據區占據著十分重要的位置。我們了解了堆內存里的分代概念,并從示意圖中直觀的感受了堆內存的結構。我們了解了堆內存中不同內存空間模塊的作用、特點及意義。這都是非常重要的知識點。
由于垃圾回收絕大多數都是發生在堆內存中,因此在課程講解的過程中,多少會涉及到垃圾回收的一些概念,此處如果不能理解的學習者,可以在學習完垃圾回收器后再次理解目前不能夠掌握的知識。