JVM性能调优:频繁的Minor GC和Major GC
先分析下Minor、MajorGC
搞清楚各种GC都代表着什么含义?
MinorGC: 从年轻代空间(包括Eden和Survivor区域)回收内存,也叫young GC
MajorGC: 从老年代空间回收内存
Full GC: 清理整个内存堆(既包括年轻代,也包括老年代)
造成的影响
会增加服务的响应时间(stw)
为什么会出现频繁的Minor GC
Minor GC发生在年轻代 ---> 年轻代内存空间分配的太少自然就会出现频繁的MinorGC
/**
* 频繁地MinorGC 和 Major GC
* --XX:NewSize=5M -XX:MaxNewSize=5M -XX:+InitialHeapSize=10M -XX:MaxHeapSize=10M -XX:SurvivorRatio=8 -XX:PretenureSizeThreshold=10M -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps
* -XX:NewSize=50M -XX:MaxNewSize=50M -XX:InitialHeapSize=100M -XX:MaxHeapSize=100M -XX:SurvivorRatio=8 -XX:PretenureSizeThreshold=10M -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps
*
* 年轻代=Eden+2Sur(From + to)
* Eden 4MB
* 2Sur 0.5 + 0.5 = 1MB
*/
@SuppressWarnings("all")
public class MoreMinorGC {
private static void minorGC() throws InterruptedException{
// 在 Eden区域放入一个1MB的对象
byte [] x = new byte[1024 * 1024];
x = new byte[1024*1024];
//会导致前面两个1MB对象成为垃圾对象
x = new byte[1024*1024];
// 将之前的3个1MB的对象都变成垃圾对象
x = null;
// 尝试在eden 区域分配一个2MB的对象,超过了5MB,会触发一次MinorGC/Young GC
byte [] y = new byte[2*1024*1024];
//睡眠1s
Thread.sleep(1000);
}
public static void main(String[] args) throws InterruptedException {
while (true){
minorGC();
}
}
}
频繁的Full GC
频繁的Full GC造成的影响及原因
影响
进程暂停响应,系统性能下降
出现原因
对象存活路径, 当老年代空间不足时,这时就会发生Full GC
Eden --> Survivor --> old Generation
/**
* 频繁的Full GC
* -Xms20M -Xmx20M -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps
*/
@SuppressWarnings("all")
public class MoreFullGC {
private static class Student{
private String name = "denny";
private int age=19;
private String gender = "male";
private LocalDate birthday = LocalDate.MAX;
public void func(){
}
}
private static final ScheduledThreadPoolExecutor executor =
new ScheduledThreadPoolExecutor(50,
new ThreadPoolExecutor.DiscardOldestPolicy());
private static void processStudent(List
studentList.forEach(student -> executor.scheduleWithFixedDelay(
student::func,2,3, TimeUnit.SECONDS
));
}
/**
* 模拟从数据库取值
* @param count
* @return
*/
private static List
List
for(int i=0;i != count;i++){
students.add(new Student());
}
return students;
}
public static void main(String[] args) throws InterruptedException {
executor.setMaximumPoolSize(50);
while (true){
processStudent(getALlStudent(100));
Thread.sleep(100);
}
}
}
26.857: [GC (CMS Initial Mark) [1 CMS-initial-mark: 13695K(13696K)] 19460K(19840K), 0.0043628 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
26.861: [CMS-concurrent-mark-start]
26.870: [CMS-concurrent-mark: 0.009/0.009 secs] [Times: user=0.02 sys=0.00, real=0.01 secs]
26.870: [CMS-concurrent-preclean-start]
26.880: [CMS-concurrent-preclean: 0.010/0.010 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]
26.880: [CMS-concurrent-abortable-preclean-start]
26.880: [CMS-concurrent-abortable-preclean: 0.000/0.000 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
26.880: [GC (CMS Final Remark) [YG occupancy: 5871 K (6144 K)]26.880: [Rescan (parallel) , 0.0045248 secs]26.885: [weak refs processing, 0.0001730 secs]26.885: [class unloading, 0.0015226 secs]26.887: [scrub symbol table, 0.0004135 secs]26.887: [scrub string table, 0.0001370 secs][1 CMS-remark: 13695K(13696K)] 19567K(19840K), 0.0068222 secs] [Times: user=0.04 sys=0.00, real=0.01 secs]
26.887: [CMS-concurrent-sweep-start]
26.891: [CMS-concurrent-sweep: 0.003/0.003 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
26.891: [CMS-concurrent-reset-start]
解读
Initial Mark
Concurrent Mark
Comcurrent Preclean
Concurrent Abortable Precleam
Final Remark
如何优化频繁的Full GC