1. 程式人生 > >JVM垃圾回收--年輕代、年老點和持久代

JVM垃圾回收--年輕代、年老點和持久代

就會 為什麽 比例 生命 system 碎片 根據 請求 min

年輕代:

  一般情況下,所有新生成的對象首先都是放在年輕代的。年輕代的目的就是盡可能快速的收集掉那些生命周期短的對象。年輕代分三個區。一個Eden區,兩個 Survivor區(分別叫from和to)Eden區與一個Survivor區的空間比例默認為8:1。

  對象在Eden區中分配,當Eden區沒有足夠空間進行分配時,虛擬機將發起一次Minor GC。如果對象仍然存活,並且能被Surivivor容納,將被移動到Survivor To區中。而在“From”區中,仍存活的對象會根據他們的年齡值來決定去向。年齡達到一定值(年齡閾值 -- 默認為15,可以通過-XX:MaxTenuringThreshold來設置)的對象會被移動到年老代中,沒有達到閾值的對象會被復制到“To”區域。經過這次GC後,Eden區和From區已經被清空。這個時候,“From”和“To”會交換他們的角色,也就是新的“To”就是上次GC前的“From”,新的“From”就是上次GC前的“To”。不管怎樣,都會保證名為To的Survivor區域是空的。Minor GC會一直重復這樣的過程,直到“To”區被填滿,“To”區被填滿之後,會將所有對象移動到年老代中。

  為什麽要分兩個Surivivor區:最大的好處就是解決了碎片化。

  因為采用的是復制算法。將原有的內存空間劃分成兩塊,每次只使用其中一塊,在垃圾回收的時候,將正在使用的內存中的存活對象復制到另一塊內存區域中,然後清除正使用過的內存區域,交換兩個區域的角色,完成垃圾回收。

  為什麽要是用復制算法:因為新生代gc比較頻繁、對象存活率低,用復制算法在回收時的效率會更高,也不會產生內存碎片。但復制算法的代價就是要將內存折半,為了不浪費過多的內存,就劃分了兩塊相同大小的內存區域survivor from和survivor to。在每次gc後就會把存活對象給復制到另一個survivor上,然後清空Eden和剛使用過的survivor。

年老代:

  長期存活的對象將進入年老代。因此,可以認為年老代中存放的都是一些生命周期較長的對象。

持久代:

  用於存放靜態文件,如今Java類、方法等。持久代對垃圾回收沒有顯著影響,但是有些應用可能動態生成或者調用一些class,例如Hibernate 等,在這種時候需要設置一個比較大的持久代空間來存放這些運行過程中新增的類。持久代大小通過-XX:MaxPermSize=<N>進行設置。

重點:

  • 在java中,對象實例都是在堆上創建。一些類信息,常量,靜態變量等存儲在方法區。堆和方法去都是線程共享的。
  • GC機制是由JVM提供,用阿裏清理需要清除的對象。回收堆內存。
  • 在從內存回收一個對象之前會調用對象的finalize()方法,但是同一個對象只會調用一次。
  • System.gc()和Runtime.gc()會向JVM發送執行GC的請求,但是JVM不保證一定會執行GC。
  • 如果堆內存不足以創建新對象。會跑出OutOfMemoryError。

JVM垃圾回收--年輕代、年老點和持久代