在知乎上看到一篇提问,因而作了个实验帮助他解答,这里整理成一篇文章分享一下。数组
先看代码以下代码:对象
1 /** 2 * Created on 2017/12/16. 3 * 4 * -verbose:gc -XX:+UseSerialGC -Xms6M -Xmx6M -Xmn2M -XX:+PrintGCDetails 5 */ 6 public class TestHeap { 7 private static final int _1MB = 1024*1024; 8 9 public static void main(String[] args) throws Exception{ 10 byte[] b = new byte[3*_1MB]; 11 } 12 }
运行时加上注释里的JVM参数,控制台打印以下进程
问题是:分配一个3m的数组,新生代只有2m,因此对象直接分配到年老代。经过打印结果也能够看出来,年老代用了3072k,正好是咱们的3m数组。可是为何新生代竟然还有68%不占用呢?get
简单猜测一下,确定是Java在运行时本身建立了一些对象占用了新生代空间。好咱们来验证下。io
将代码为何也不作:class
/** * Created on 2017/12/16. * * -verbose:gc -XX:+UseSerialGC -Xms6M -Xmx6M -Xmn2M -XX:+PrintGCDetails */ public class TestHeap { private static final int _1MB = 1024*1024; public static void main(String[] args) throws Exception{ //byte[] b = new byte[3*_1MB]; } }
控制台打印以下:map
即便执行建立字节数组语句,新生代依旧被占用68%。能够说咱们假象成立。gc
不信?im
那好吧,我们就打印下此时Java堆空间里的对象来看看。技术
我们是用jmap命令来打印出堆里的对象看看,顺便复习下jmap的使用。
咱们使用以下命令:
jmap -histo:live pid
注意:此命令不能在线上执行,由于会触发JVM的fullgc。
代码不变,依旧是注释掉字节数组的建立语句。只不过为了方便执行jmap命令,我们让它暂停下,以防进程退出。
/** * Created on 2017/12/16. * * -verbose:gc -XX:+UseSerialGC -Xms6M -Xmx6M -Xmn2M -XX:+PrintGCDetails */ public class TestHeap { private static final int _1MB = 1024*1024; public static void main(String[] args)throws Exception{ //byte[] b = new byte[3*_1MB]; Thread.sleep(100000L); } }
执行jmap命令结果以下(部分截图):
看到了,咱们啥都不作都有1544个char数组对象,120个byte数组对象等等。
------------------------------------------------------------------------------
这里是跟阿里的技术大牛建立的一个圈子,主要面向初学者提供辅导帮助。有兴趣的能够加入。