JVM堆空间结构及垃圾回收过程分析
Java堆空间
新生代存放新生对象或者年龄不大的对象,老年代存放老年对象。from和to区域是两块大小相等,可以互换角色的内存空间,详细内容会在以后的博文中介绍
在大多数情况,对象首先被分配在eden区,在一次新生代回收之后,如果对象还存活,则会进入from或者to区,之后每经过一次新生代回收,对象如果存活,年龄就会加1,当对象年龄达到一定条件后,就会被认为是老年对象,从而进入老年代。
垃圾回收追踪
参数配置
-Xms | 初始堆大小。如:-Xms256m |
---|---|
-Xmx | 最大堆大小。如:-Xmx512m |
-Xmn | 新生代大小。通常为 Xmx 的 1/3 或 1/4。新生代 = Eden + 2 个 Survivor 空间。实际可用空间为 = Eden + 1 个 Survivor,即 90% |
-Xss | JDK1.5+ 每个线程堆栈大小为 1M,一般来说如果栈不是很深的话, 1M 是绝对够用了的。 |
-XX:NewRatio | 新生代与老年代的比例,如 –XX:NewRatio=2,则新生代占整个堆空间的1/3,老年代占2/3 |
-XX:SurvivorRatio | 新生代中 Eden 与 Survivor 的比值。默认值为 8。即 Eden 占新生代空间的 8/10,另外两个 Survivor 各占 1/10 |
-XX:PermSize(JDK1.8废除) | 永久代(方法区)的初始大小 |
-XX:MaxPermSize (JDK1.8废除) | 永久代(方法区)的最大值 |
-XX:+PrinGCDetails | 打印 GC 信息 |
-XX:+HeapDumpOnOutOfMemoryError | 让虚拟机在发生内存溢出时 Dump 出当前的内存堆转储快照,以便分析用 |
-XX:MaxMetaspaceSize | 限制元空间大小,默认情况下类的元空间分配由可用本机内存量决定 |
测试代码:
1 | public class TestLocalVar { |
使用-XX:+PrintGC来打印日志
1 | [GC (System.gc()) 8806K->6768K(125952K), 0.0070835 secs] //Major GC仅为新生代GC |
数组占用空间为6MB,可见第一次(GC和Full GC为一次)垃圾回收并没有能处理
第二次6722k->514k,回收6208k(约为6M),由此可见数组在第二次垃圾回收时被成功回收,当前可用堆空间总和为125952k(123M)
使用-XX:+PrintGCDetails获得详细信息,标号符和分割线为方便观察,后期人为添加的
1 | 1* [GC (System.gc()) [PSYoungGen: 8806K->616K(38400K)] 8806K->6760K(125952K), 0.0122872 secs] |
1* 新生区回收效果(8806K->616K)整个堆(8806K->6760k)
2* 同时回收新生代、老年代、和元空间
新生区清空(616K->0K),老年区(6144K->6658K),整个堆(6760K->6658K),【这里总空间变化与新生区和老年区变化总量不相等,按道理应该相等的,有哪位读者知道原因,麻烦留下言】元空间不变
User代表用户态CPU耗时,sys表示系统CPU耗时,real表示GC实际经历时间
3和4类似,这里就不过多解释了
5* 虚拟机会在推出前打印堆详细信息,描述了堆各个区间使用情况
PSYoungGen:新生区总大小38400k,使用998k,[0x00000000d5e00000,0x00000000d5ef9b70,0x00000000d7e80000)分别表示新生代下界,当前上界和上界
上界-下界:(0x00000000d7e80000-0x00000000d5e00000)/1024 = 33280k为eden大小(当前堆空间的理论可用最大值,新生对象总会放在eden中,所以并非真正总堆空间,真正堆空间也不是total=8755k,因为虚拟机同时只能使用from和to中的一个,所以系统分配的堆空间总大小其实是33280+5120*2)
当前上界-下界:(0x00000000d5ef9b70-0x00000000d5e00000)/1024=997.18k等于已使用的空间
关于这部分空间的计算,参考http://www.blogjava.net/fancydeepin/archive/2013/09/29/jvm_heep.html
- ParOldGen类似
补充虚拟机相关设置
-XX:+PrintHeapAtGC在每次GC前后打印堆信息,获得更全面的堆信息
-XX:+PrintGCTimeStamps,输出每次GC发生在虚拟机启动后的时间偏移量
-XX:+PrintGCApplicationConcurrentTime打印应用程序的执行时间
-XX:+PrintGCApplicationStoppedTime打印应用程序由于G而产生的停顿时间
-XX:PrintReferenceGC跟踪系统内的软引用、弱引用和Finallize队列
扩展
默认情况下GC日志会在控制台输出,不利于分析及定位问题,虚拟机允许将GC日志以文件形式输出
用-Xloggc:filepath指定