通过前两节,我们了解到了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