实验内容
实验案例
- 堆的大小;
- 堆的新生代和老年代比例;
- 堆的新生代中Eden和Survival区比例;
- java对象的成年标准;
- 方法区大小;
- 内存溢出;
- 手动触发GC;
- 指定垃圾回收器;
实验参数
//堆总内存大小
-Xmx500m
//堆初始化内存大小
-Xms500m
新生代和老年代内存分配比例
-XX:NewRatio=4
新生代的Eden和Survival的比值(Eden:From:To)8:1:1
-XX:SurvivorRatio=8
老年代的标准(有效区间是0到15),3岁
-XX:MaxTenuringThreshold=3
方法区大小(初始值和最大值)
-XX:MetaspaceSize=100M -XX:MaxMetaspaceSize=300M
实验工具
- JDK1.8(jdk1.8.0_131)
- jvisualvm.exe + GC插件
- jmap -heap pid
实验过程
Java代码
import java.util.ArrayList;
import java.util.List;
public class App {
//老年代对象列表,测试Old一直增加
static List<String> oldObjectList = new ArrayList<String>();
public static void main(String[] args) {
//初始化老年代对象
for (int i = 0; i < 10000; i++) {
oldObjectList.add("string"+i);
}
int index = 0 ;
//让程序无限运行
while(true){
//创建临时对象列表,测试Eden、From和To的GC过程
List<String> tempObjectlist = new ArrayList<String>();
for (int i = 0; i < 10000; i++) {
tempObjectlist.add("string"+i);
oldObjectList.add("string"+(index+i));
}
//测试手动GC
System.gc();
//方便观察过程,放慢执行时间
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
查看默认JVM参数
启动程序后,使用java命令“jmap -heap pid”
自定义参数
- 准备参数
-Xmx500m -Xms500m
-XX:NewRatio=4 -XX:SurvivorRatio=8 -XX:MaxTenuringThreshold=3
-XX:MetaspaceSize=100m
-
加入程序启动项
-
对比前后参数变化
-
jvisualvm可视化工具
注意这里新生代和老年代的大小是100:400;
Eden和S0\S1的大小是80:10:10
-
观察From表示的变化
-
内存溢出
- 手动GC
总结
- JVM调优就是参数配置;
- 常用参数:堆大小、方法区大小、分代区域比例、成年标准;
- 方法区在1.8之后使用元素区概念,基本不用关心方法区溢出问题;
- 内存大小分为2种,最大空间和初始化空间;如果只有一个应用,建议两者相等;如果多个应用在一台服务器,初始空间可以先小一点;
- 新生代的大小有3种设置方式,XX:NewSize > -Xmn >-XX:NewRatio;建议用比例模式;
- 手动GC尽量不要用,GC的暂停特性会影响整体性能;
- 自定义垃圾回收器意义不大,JVM的智能模式足够了;如果非要配置,吞吐量优先采用并行收集器(ParallelGC+ParallelOldGC),减少回收时间;响应时间优先采用并发收集器(ParNewGC+ConcMarkSweepGC),增加程序运行机会。