1.為什么會有年輕代
我們先來屢屢,為什么需要把堆分代?不分代不能完成他所做的事情么?其實不分代完全可以,分代的唯一理由就是優化GC性能。你先想想,如果沒有分代,那我們所有的對象都在一塊,GC的時候我們要找到哪些對象沒用,這樣就會對堆的所有區域進行掃描。而我們的很多對象都是朝生夕死的,如果分代的話,我們把新創建的對象放到某一地方,當GC的時候先把這塊存“朝生夕死”對象的區域進行回收,這樣就會騰出很大的空間出來。
2.年輕代中的GC
HotSpot JVM把年輕代分為了三部分:1個Eden區和2個Survivor區(分別叫from和to)。默認比例為8:1,為啥默認會是這個比例,接下來我們會聊到。一般情況下,新創建的對象都會被分配到Eden區(一些大對象特殊處理),這些對象經過第一次Minor GC后,如果仍然存活,將會被移到Survivor區。對象在Survivor區中每熬過一次Minor GC,年齡就會增加1歲,當它的年齡增加到一定程度時,就會被移動到年老代中。
因為年輕代中的對象基本都是朝生夕死的(80%以上),所以在年輕代的垃圾回收算法使用的是復制算法,復制算法的基本思想就是將內存分為兩塊,每次只用其中一塊,當這一塊內存用完,就將還活着的對象復制到另外一塊上面。復制算法不會產生內存碎片。
在GC開始的時候,對象只會存在於Eden區和名為“From”的Survivor區,Survivor區“To”是空的。緊接着進行GC,Eden區中所有存活的對象都會被復制到“To”,而在“From”區中,仍存活的對象會根據他們的年齡值來決定去向。年齡達到一定值(年齡閾值,可以通過-XX:MaxTenuringThreshold來設置)的對象會被移動到年老代中,沒有達到閾值的對象會被復制到“To”區域。經過這次GC后,Eden區和From區已經被清空。這個時候,“From”和“To”會交換他們的角色,也就是新的“To”就是上次GC前的“From”,新的“From”就是上次GC前的“To”。不管怎樣,都會保證名為To的Survivor區域是空的。Minor GC會一直重復這樣的過程,直到“To”區被填滿,“To”區被填滿之后,會將所有對象移動到年老代中。
3.一個對象的這一輩子
我是一個普通的Java對象,我出生在Eden區,在Eden區我還看到和我長的很像的小兄弟,我們在Eden區中玩了挺長時間。有一天Eden區中的人實在是太多了,我就被迫去了Survivor區的“From”區,自從去了Survivor區,我就開始漂了,有時候在Survivor的“From”區,有時候在Survivor的“To”區,居無定所。直到我18歲的時候,爸爸說我成人了,該去社會上闖闖了。於是我就去了老年代那邊,老年代里,人很多,並且年齡都挺大的,我在這里也認識了很多人。在老年代里,我生活了20年(每次GC加一歲),然后被回收。
4.有關年輕代的JVM參數
1)-XX:NewSize和-XX:MaxNewSize
用於設置年輕代的大小,建議設為整個堆大小的1/3或者1/4,兩個值設為一樣大。
2)-XX:SurvivorRatio
用於設置Eden和其中一個Survivor的比值,這個值也比較重要。
3)-XX:+PrintTenuringDistribution
這個參數用於顯示每次Minor GC時Survivor區中各個年齡段的對象的大小。
4).-XX:InitialTenuringThreshol和-XX:MaxTenuringThreshold
用於設置晉升到老年代的對象年齡的最小值和最大值,每個對象在堅持過一次Minor GC之后,年齡就加1。
jvm 中的 “永生代”
“方法區” 主要存儲的信息包括:常量信息,類信息,方法信息,而且是全局共享的(多線程共享);
jvm 有多種實現方式(不同的廠商); 並不是所有的jvm 都有永生代的概念;
通常情況下, 很多人把 “方法區” 和“永生代” 對等; 換句話說,是利用“永生代”
去實現“方法區”, 這樣可能導致OOM (因為“永生代”的大小是可以通過-XX:PermSize -XX:MaxPermSize)
設置的; 但是在J9 和JRockit jvm中,方法區使用的內存上限是4G(32位系統可表示的最大范圍),不
會存在該問題。
如果利用“永生代”實現“方法區”的垃圾收集, 主要是收集常量池和對類型進行卸載; 通常情況下,這個區域的
收集效率比較低。
一: 常量的回收比較容易
二: 類信息的回收需要滿足的條件:
1 . 該類所有的實例已經被回收,JVM中沒有任何類的實例;
2. 加載該類的ClassLoader被回收;
3. 該類對應的java.lang.class沒有地方引用
Note: 可以使用-verbose:class以及-XX:TraceClassLoading和-XX:TraceClassUnLoading來查看類的加載和卸載情況。

