JAVA虚拟机新生代,包括eden space+2个survivor空间。
新生代用来存放新近创建的对象,新生代的特点是对象更新速度快,在短时间内产生大量的“死亡对象”。对年轻代的垃圾回收称作次级回收 (minor gc)
1、新生代与次级回收
新生代分为三个区域, 一个eden spac , 2个大小相同的survivor, 应用程序只能使用一个eden和一个survivor, 当发生初级垃圾回收的时候,gc挂起程序, 然后将eden和survivorA中的存活对象复制到另外一个非活动的survivorB中,然后一次性清除eden和survivor,将原来的survivorB标记成为survivoA. 将在指定次数回收后仍然存在的对象移动到老年代中, 次级回收后,得到一个空的可用的eden.
JVM调优主要是针对内存管理方面的调优,包括控制各个代的大小,GC策略。由于GC开始垃圾回收时会挂起应用线程,严重影响了性能,调优的目是为了尽量降低GC所导致的应用线程暂停时间、减少Full
GC次数。
2、新生代大小调优
新生代最关键参数:-Xms、 -Xmx
、-Xmn
、-XX:SurvivorRatio、-XX:MaxTenuringThreshold、-XX:PermSize、-XX:MaxPermSize
-Xms、 -Xmx
通常设置为相同的值,避免运行时要不断扩展JVM内存,这个值决定了JVM heap所能使用的最大内存。
-Xmn 决定了新生代空间的大小,新生代Eden、S0、S1三个区域的比率可以通过-XX:SurvivorRatio来控制(假如值为
4 表示:Eden:S0:S1 = 4:3:3 )
-XX:MaxTenuringThreshold
控制对象在经过多少次minor GC之后进入老年代,此参数只有在Serial
串行GC时有效。
-XX:PermSize、-XX:MaxPermSize
用来控制方法区的大小,通常设置为相同的值。
1.避免新生代大小设置过小
当新生代设置过小时,会产生两种比较明显的现象,一是minor GC次数频繁,二是可能导致 minor GC对象直接进入老年代。当老年代内存不足时,会触发Full
GC。
2.避免新生代设置过大
新生代设置过大,会带来两个问题:一是老年代变小,可能导致Full GC频繁执行;二是 minor GC
执行回收的时间大幅度增加。
3.避免Survivor区过大或过小
-XX:SurvivorRatio参数的值越大,就意味着Eden区域变大,minor
GC次数会降低,但两块Survivor区域变小,如果超过Survivor区域内存大小的对象在minor
GC后仍没被回收,则会直接进入老年代;
-XX:SurvivorRatio参数值设置过小,就意味着Eden区域变小,minor
GC触发次数会增加,Survivor区域变大,意味着可以存储更多在minor GC后任存活的对象,避免其进入老年代。
4.合理设置对象在新生代存活的周期
新生代存活周期的值决定了新生代对象在经过多少次Minor GC后进入老年代。因此这个值要根据自己的应用来调优,Jvm参数上这个值对应的为-XX:MaxTenuringThreshold,默认值为15次。
3、查看2个survivor空间交换的源代码
源代码,仅供参考
package com.gc;
import java.util.ArrayList;
import java.util.Random;
/**
* 简单的应用,能够看到survivor空间交换,用JDK自带的jstat查看
* 参数:-Xms30m -Xmx60m
*
* @author 范芳铭
*/
public class EasySurvivorChange {
public byte[] placeHolder =new byte[1 * 1024]; //
占位符
public static void main(String[]args) throws Exception {
while (true) {
Random random =new Random();
int loops =random.nextInt(10000);
EasySurvivorChangejstat = new EasySurvivorChange();
System.out.println("......正在构建对象:" + loops + "(个)");
jstat.getLoop(loops);//多次循环,产生大量对象
Thread.sleep(10);
}
}
public void getLoop(int size){
ArrayList<EasySurvivorChange>list = new ArrayList<EasySurvivorChange>();
for (int i = 0; i <size; i++) {
EasySurvivorChangejstat = new EasySurvivorChange();
list.add(jstat);
}
}
}
4、用jstat查看survivor空间交换
C:\Program Files\Java\jdk1.6.0_25\bin>jps
8068 Jps
2384
7248 EasySurvivorChange
C:\Program Files\Java\jdk1.6.0_25\bin>jstat -gc 7248 250 6
S0C S1C S0U S1U EC EU
128.0 64.0 0.0 63.8 1024.0 0.0
128.0 128.0 0.0 127.6 1152.0 0.0
64.0 64.0 63.6 0.0 896.0 0.0
64.0 64.0 0.0 64.0 896.0 0.0
64.0 64.0 0.0 63.8 896.0 0.0
64.0 64.0 0.0 0.0 896.0 0.0
S0C表示当前S0的容量 (KB),S1C表示当前S1的容量
(KB),S0U表示当前S0使用的大小 (KB),S1U表示当前S1使用的大小(KB).我们知道,两个Survivor区的数据是进行交换标记的,在这里能够很明显看出,S0U和S1U的空间使用情况是在交替进行的。