通過前兩節,我們瞭解到了java的大概內存結構,其實JVM的內存分佈還是比較複雜的,並且各個java虛擬機不相同,內部結構會有相應的變化,有些時候我們將其理解爲概念模型纔不會有太多的煩惱,雖然前面的文字描述了那麼多關於內存模型的東西,但是可能在你現在安裝的JVM中未必就完全按照如此進行分佈,需要視具體的版本而定。
爲什麼還要有這一小節的存在呢?本來想要開始java垃圾回收的文章,但是在整理垃圾回收相關資料的時候,我又決定,需要對堆內存做進一步的劃分說明(其實這本身是JVM對垃圾回收的一個規範模型),這樣,在理解起來以後的垃圾回收機制就不會顯得有那麼多的陌生感。
本節中將有如下的一些內容進行說明:
1、堆內存的分佈
2、通過jps和jstat命令查看堆內存的情況
3、通過一個dump信息查看堆內存的情況
第一:java堆內存的分佈
java的堆內存還可以進一步的細分,現在比較主流的劃分爲Eden,兩個Survivor from,Survivor to ,permanent,tenured,如下圖所示,其中Eden,兩個Survivor是在新生代中,permanent和tenured在老年代中,什麼是新生代和老年代,說的通俗一點就是一個是存放剛創建對象的內存空間,一個是存放早期創建對象的內存空間,如下圖所示:
(上面的圖,其中From Survivor 單詞寫反了,To Survivor 也寫反了,發佈之後才注意到)
解釋一下上面的圖,當創建一個對象的時候,該對象將被存放到Eden區,如果經過了一次垃圾回收,Eden有存活的對象,將會被存放到Survivor區,也就是說Survivor存放的是新一輪GC開始之前存活的對象,如果對象在Survivor中經常使用或者說Survivor空間不足,會將對象放到老年代也就是Tenured區,如果在垃圾回收之後,Survivor沒有足夠的空間,需要向老年代申請空間的時候,老年代此時也是由於空間不夠,此時將會拋出OutOfMemoryError,換言之,堆中經常出現內存溢出的區域是兩個Survivor和Tenured區。
第二:jps和jstat命令介紹
第三:生成dump並且簡單說明
好了,命令暫時說道這裏,在這快,我們做一個堆內存溢出的實驗,並且進行jstat分析,然後看一下其中堆內存空間的變化情況。看看如下的java代碼:import java.util.List;
import java.util.ArrayList;
/**
*@desc 進行堆內存溢出的測試
*@author wangwenjun(QQ:532500648)
*@since 1.0.0
* */
public class HeapMemoryTest
{
static class Test{}
public static void main(String[] args)
{
List list = new ArrayList();
/*休眠時間長一點,是爲了執行jps和jstat命令先*/
try{
Thread.sleep(10000);
}catch(Exception e){};
while(true)
{
list.add(new Test());
try{
Thread.sleep(2);
/*休眠,能更好的查看到內存的變化*/
}catch(Exception e){};
}
}
}
java -verbose:gc -Xms10M -Xmx10M -XX:+PrintGCDetails HeapMemoryTest