1. 程式人生 > >Java虛擬機器堆的記憶體分配和回收

Java虛擬機器堆的記憶體分配和回收

java記憶體分配和回收,主要就是指java堆的記憶體分配和回收。java堆一般分為2個大的區域,一塊是新生代,一塊是老年代。在新生代中又劃分了3塊區域,一塊eden區域,兩塊surviver區域。一般稱為from surviver和to surviver。這些區域的大小可以自己指定。比如:(-Xms20M 表示可用堆記憶體大小;-Xmx40M 表示最大堆記憶體,在堆記憶體大小不夠時,會擴充套件到最大堆記憶體;-Xmn10M 表示新生代記憶體大小)。

新生代中的物件會在eden區域分配,然後eden區域的記憶體不夠物件分配的時候,會發生一次minor GC。這時候,會把from surviver和eden區域的存活的物件複製到to surviver區域中,這次的to surviver區域變成了下次的form surviver。那麼survier區域和eden區域如何按比例劃分呢?由於java中很多物件都是朝生夕死的,被分配出來後,馬上就會被垃圾回收,存活下來的物件很少,而存活下來的物件都會到surviver區域,所以sun公司覺得surviver區域太大不好,surviver區域大了,eden就小了,這樣分配記憶體的空間就小了。所以sun公司預設surviver 區域和eden區域的比例為 from surviver :to surviver : eden為1:1:8。

那麼大家會覺得,surviver區域的物件每次Minor GC都會存活下來,那麼就會越積越多,會不會導致surviver區域存不下呢?答案時,確實會存不下,所以老年代這時候出場了。

surviver區域的物件,在經過若干次Minor GC之後,會升級成為老年代物件,從而進入老年代。jvm預設時15次gc,新時代還存活就進入老年代。當然,也有可能surviver區域都沒有等到15次,surviver卻滿了,不用擔心,這時候jvm會把平均年齡偏大的物件,統統送入老年代中。

可能大家還有疑問,如果一上來新生成的物件非常大,eden區這小船裝不下會怎麼辦?那也沒問題,直接就升級啦,成為老年人啦。不過老年人也是會越來越多的,jvm當然不會容忍這些屍體沒人收變成木乃伊,當然要回收它們啦。當老年代記憶體不夠分配的時候,這時候系統就會發生一次FULL GC,把老年代的垃圾也回收了。

在java虛擬機器中,新生代和老年代的垃圾回收是分開的。java虛擬機器提供給我們好幾個垃圾回收器選擇。

新生代收集器:

1.Serial收集器,單執行緒收集器,採用複製演算法,由於單執行緒,所有在java伺服器端開發中,肯定不會去用它。

2.ParNew收集器,是Serial的多執行緒版本,採用複製演算法,可以說是java伺服器端首選收集器。 

3.Parallel Scavenge收集器,多執行緒,採用複製演算法,此收集器最大的特點在可控制垃圾回收的吞吐量,此垃圾收集器適用於非實時和使用者互動的伺服器,適用於後臺跑演算法,跑job的伺服器。

老年代收集器:

1.Serial old, Serial的老年版本。

單執行緒的,採用標記-整理演算法,很遺憾,同樣不適合伺服器中使用。

2.Parallel old,Parallel Scavenge的老年版本。多執行緒,標記-整理演算法,此收集器和Parallel Scavenge特點一樣,這2種收集器搭配,對於跑job的伺服器來說,是很不錯的,不過還的侃實際應用來配置,萬一job任務的時間間隔很短,這時候在gc,可能就有問題,所以也不能一味最求吞吐量。

3.cms收集器,標記-清除演算法,此收集器特點是,垃圾回收停頓時間短,重視伺服器響應速度,給使用者帶來好的體驗。

最後是新生代和老年代通吃的收集器,G1收集器。G1可以說非常強悍,除了吞吐量需求大的,其它的都可以被g1代替了。總之,以後伺服器要體驗好的,就用g1收集器,要吞吐量大的就用Parallel套裝。