JVM性能调优:频繁的Minor GC和Major GC

JVM性能调优:频繁的Minor GC和Major GC

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){

studentList.forEach(student -> executor.scheduleWithFixedDelay(

student::func,2,3, TimeUnit.SECONDS

));

}

/**

* 模拟从数据库取值

* @param count

* @return

*/

private static List getALlStudent(int count){

List students = new ArrayList<>(count);

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

相关文章