Fork me on Gitee

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

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

先分析下Minor、MajorGC

搞清楚各种GC都代表着什么含义?

  • MinorGC: 从年轻代空间(包括Eden和Survivor区域)回收内存,也叫young GC
  • MajorGC: 从老年代空间回收内存
  • Full GC: 清理整个内存堆(既包括年轻代,也包括老年代)

image-20250329164429711

造成的影响

会增加服务的响应时间(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();
        }
    }
}

image-20250329171448131

频繁的Full GC

频繁的Full GC造成的影响及原因

影响

  • 进程暂停响应,系统性能下降

出现原因

  • 对象存活路径, 当老年代空间不足时,这时就会发生Full GC

Eden --> Survivor --> old Generation

image-20250329205920776

/**
 * 频繁的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<Student> studentList){
        studentList.forEach(student -> executor.scheduleWithFixedDelay(
                student::func,2,3, TimeUnit.SECONDS
        ));
    }

    /**
     * 模拟从数据库取值
     * @param count
     * @return
     */

    private static List<Student> getALlStudent(int count){
        List<Student> 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

image-20250329212442199

Concurrent Mark

image-20250329212537825

Comcurrent Preclean

image-20250329212608081

Concurrent Abortable Precleam

image-20250329212640866

Final Remark

image-20250329212706936

如何优化频繁的Full GC

image-20250329212245754

posted @ 2025-03-30 21:48  shine-rainbow  阅读(181)  评论(0)    收藏  举报