5、JVM之堆內存

堆結構分代圖

jpg

堆結構分代的意義

  Java虛擬機根據對象存活的週期不一樣,把堆內存劃分爲幾塊,通常分爲新生代、老年代和永久代(對HotSpot虛擬機而言),這就是JVM的內存分代策略。
  堆內存是虛擬機管理的內存中最大的一塊,也是垃圾回收最頻繁的一塊區域,咱們程序全部的對象實例都存放在堆內存中。給堆內存分代是爲了提升對象內存分配和垃圾回收的效率。試想一下,若是堆內存沒有區域劃分,全部的新建立的對象和生命週期很長的對象放在一塊兒,隨着程序的執行,堆內存須要頻繁進行垃圾收集,而每次回收都要遍歷全部的對象,遍歷這些對象所花費的時間代價是巨大的,會嚴重影響咱們的GC效率。
  有了內存分代,狀況就不一樣了,新建立的對象會在新生代中分配內存,通過屢次回收仍然存活下來的對象存放在老年代中,靜態屬性、類信息等存放在永久代中,新生代中的對象存活時間短,只須要在新生代區域中頻繁進行GC,老年代中對象生命週期長,內存回收的頻率相對較低,不須要頻繁進行回收,永久代中回收效果太差,通常不進行垃圾回收,還能夠根據不一樣年代的特色採用合適的垃圾收集算法。分代收集大大提高了收集效率,這些都是內存分代帶來的好處。java

堆結構分代

​ Java虛擬機將堆內存劃分爲新生代、老年代和永久代,永久代是HotSpot虛擬機特有的概念(JDK1.8以後爲metaspace替代永久代),它採用永久代的方式來實現方法區,其餘的虛擬機實現沒有這一律念,並且HotSpot也有取消永久代的趨勢,在JDK 1.7中HotSpot已經開始了「去永久化」,把本來放在永久代的字符串常量池移出。永久代主要存放常量、類信息、靜態變量等數據,與垃圾回收關係不大,新生代和老年代是垃圾回收的主要區域。算法

新生代(Young Generation)性能

  新生成的對象優先存放在新生代中,新生代對象朝生夕死,存活率很低,在新生代中,常規應用進行一次垃圾收集通常能夠回收70% ~ 95% 的空間,回收效率很高。
  HotSpot將新生代劃分爲三塊,一塊較大的Eden(伊甸)空間和兩塊較小的Survivor(倖存者)空間,默認比例爲8:1:1。劃分的目的是由於HotSpot採用複製算法來回收新生代,設置這個比例是爲了充分利用內存空間,減小浪費。新生成的對象在Eden區分配(大對象除外,大對象直接進入老年代),當Eden區沒有足夠的空間進行分配時,虛擬機將發起一次Minor GC。
  靜態版GC開始時,對象只會存在於Eden區,From Survivor區和To Survivor區是空的(做爲保留區域)。GC進行時,Eden區中全部存活的對象都會被複制到From Survivor區。若From Survivor區也滿了,再對該區進行垃圾回收,而後把全部存貨的對象複製到To Survivor區。那若是To Survivor區也滿了呢?再移動到養老區。若養老區也滿了,那麼這個時候將產生Major GC(FullGC),進行養老區的內存清理。若養老區執行了Full GC以後發現依然沒法進行對象的保存,就會產生OOM異常「OutOfMemoryError」,一般Full GC 所消耗的性能是Minor GC的十倍以上。spa

動態版首先,當Eden區滿的時候會觸發第一次GC,把還活着的對象拷貝到SurvivorFrom區,當Eden區再次觸發GC的時候會掃描Eden區和From區,對這兩個區進行垃圾回收,通過此次回收後還存活的對象,則直接賦值到To區域(若是有對象的年齡已經達到了老年的標準,則賦值到老年代區),同時把這些對象的年齡加+1。而後,清空Eden和From區中的對象,接着, From Survivor區和To Survivor區會交換它們的角色,也就是新的To Survivor區就是上次GC清空的From Survivor區,新的From Survivor區就是上次GC的To Survivor區,總之,無論怎樣都會保證To Survivor區在一輪GC後是空的。部分對象會在From和To區域中複製來複制去,如此交換15次(由JVM參數MaxTenuringThreshold決定默認是15),最終若是仍是存活,就存入老年代。對象

老年代(Old Generationn)blog

​ 在新生代中經歷了屢次(具體看虛擬機配置的閥值)GC後仍然存活下來的對象會進入老年代中。老年代中的對象生命週期較長,存活率比較高,在老年代中進行GC的頻率相對而言較低,並且回收的速度也比較慢。生命週期

永久代(Permanent Generationn)(JDK1.8後移除)內存

​ 永久代存儲類信息、常量、靜態變量、即時編譯器編譯後的代碼等數據。字符串

​ 永久存儲區是一個常駐內存區域,用於存放JDK自身所攜帶的Class,Interface的元數據,也就是說它存儲的是運行環境必須的類信息,被裝載進此區域的數據是不會被垃圾回收器回收掉的,關閉JVM纔會釋放此區域所佔用的內存。編譯器

元空間(Meta Space)

元空間是JDK 1.8 以後纔有的,功能和永久代相似。惟一到的區別是,永久代使用的是JVM的堆內存空間,而元空間使用的是物理內存,直接受到本機的物理內存限制。

所以,默認狀況下,元空間的大小僅受本地內存限制。類的元數據放入native memory,字符串池和類的靜態變量放入java堆中,這樣能夠加載多少類的元數據就再也不由MaxPermSize控制,而由系統實際可用空間來控制。

相關文章
相關標籤/搜索