憨人筆記之JVM-運行時數據區(堆空間)

堆空間

在Java虛擬機運行時數據區中,堆內存是各種內存中最大的一塊。堆內存的建立伴隨着虛擬機的啓動而建立。全部對象實例的建立都是在堆內存中。在Java虛擬機規範中明確的描述了:全部對象實例以及數組都要在堆上分配內存空間。垃圾回收的主要區域也是發生在堆內存中。算法

從內存回收的角度來看,如今的垃圾收集器基本上都採用了分代收集算法,因此,堆內存又能夠分爲新生代老年代數組

在爲新建立的對象分配內存時,爲了保證併發的安全,在堆空間中會爲每一個線程建立一個TLAB(本地線程分配緩衝區)區域,因此雖然堆內存是線程共享的,可是在內存分配的角度來看,它又可以劃分出多個線程私有的TLAB區域。安全

固然,重點關注的仍是堆內存中的新生代與老年代,首先看一下堆空間中新生代與老年代的劃分比例:併發

新生代與老年代的空間大小比例爲1:2,而在新生代中還劃分了三個區域:Eden區、Surivivor From區、Surivivor To區。它們之間的比例分別爲8:1:1。下面來詳細分析不一樣年齡代的區域。性能

新生代

新生代主要做用是用來放置新建立的對象,任何一個對象初次建立時都會被分配至此區域。在新生代中,98%的對象都是"朝生夕死"的,並不須要一比一來劃份內存空間,而是講內存空間劃分爲兩個大的區域:Eden區、Survivor區(其中,Surivivor區域又被劃分紅兩個Survivor From區,Survivor To區域)。每一次內存分配都是使用Eden區和Survivor區域中的一塊。既然劃分了三個區域,那麼就來講說對象在這三個區域中怎麼流轉的。線程

  1. 首先,新生對象會被分配在Eden區域,會觸發一次Monir GC,此時會講Eden區中還存活的對象複製到第一個Surivor區域(Surivor From)
  2. 繼續建立對象,當Eden區內存不足覺得新對象分配內存空間的時候,會再次觸發Monir GC,此時就會將Eden區和第一個Surivor區域中還存活的對象複製到另一個Survivor區中(Survivor To),而後Eden區和第一個Survivor區會被清空,以便爲新對象騰出內存空間。
  3. 繼續建立對象,此時第一個Survivor區域已經爲空,第二個Survivor區域中已經存在了上次被複制過來的對象,那麼再建立對象的時候,就只會在Eden區和第二個Survivor區中操做。
  4. 如此往復循環,當對象被複制的次數達到16次時,就會被送至老年代中。

強調的一點是,新生代中,只會Eden區和Survivor區域其中的一塊被同時使用,另外一塊Survivor區域始終爲空的。cdn

爲何要劃分出兩個Survivor區域呢?

上面說到,Survivor區域中,始終會有一塊Survivor區域被空置,那麼在有限的堆內存中,豈不是形成了內存的浪費。首先了解一下劃分出Survivor區域的意義在哪裏。對象

試想若是沒有劃分Survivor區域,那麼Eden區每進行一次Monir GC,都會將對象直接送入老年代,老年代將會很快被填滿,從而觸發Major GC。Major GC的執行效率相對Monir GC來講效率慢了十倍以上。那麼與有Survivor區的狀況相比,Major GC觸發的頻率則會相對提升,嚴重的將會影響到程序執行及相應的速度。blog

若是存在Survivor區域,它能夠做爲一個緩衝區,當Eden區觸發Monir GC後,對象不直接送往老年代,而是複製到Survivor區,相對來講就能夠下降觸發Major GC的機率。因此,Survivor區存在的根本意義是:減小對象被送往老年代的頻率,從而減小Major GC和Full GC的發生,Survivor能夠保證在經歷了16次Monir GC還能在新生代存活的對纔會被送到老年代內存

另一個方面就是Survivor區有效的解決了內存的碎片化。回顧以前說到的新生代對象流轉流程。新建立的對象都被分配在Eden區,一旦該區域的內存滿了,會觸發Monir GC,而後對象會被從Eden送至Survivor區,往復循環。由此,問題來了,在進行Monir GC時,Eden和Survivor區都有一切存活的對象,此時將Eden取中的對象強行存放到Survivor區時,明顯兩部分的對象所佔用的內存空間是不連續的,也就致使了內存的碎片化。

內存碎片化最終的結果就是會嚴重影響到程序的性能。試想當堆空間被散佈的對象佔據了不連續的內存,當有一個內存需求較大的對象被建立的時,堆中可能就沒有足夠大的連續內存空間來分配給該對象,那麼就會觸發Full GC。

若是將Survivor區劃分紅兩塊。在Eden區剛剛建立新對象時,經歷一次Monir GC,Eden區存活的對象就被被複制移動到第一塊Survivor區中,Eden被清空,等Eden區再滿了的時,再次觸發Monir GC,Eden區和第一塊Survivor區存活的對象會被複制移動到第二塊Survivor區。Eden和第一塊Survivor區域被清空。

因此,爲何要劃分兩個Survivor區呢?

  • Survivor區做爲新生代與老年代之間的緩衝區,能夠下降將對象送往老年代的頻率,老年代也就沒那麼快就被對象堆滿而致使發生垃圾回收
  • Survivor中採用的複製算法,複製算法能有效的下降內存的碎片化

老年代

老年代主要存放的是經歷過幾回垃圾回收以後還存活的對象,剛剛在說到新生代對象的複製轉移的時候,當被標記了16次的對象若是還存活着,就會被送入到老年代。

另一種就是較大的對象,較大的對象也就被直接送入到老年代中。


不怕路歹行不怕大雨淋,心上一字敢 面對個人夢,甘願來做憨人。 --<憨人>

相關文章
相關標籤/搜索