【演练】Java应用频繁Full GC, OOM

2022-08-02,,,,

目录

    • 前言
    • 演练代码
    • 故障现象
    • jmap查看
    • 问题原因定位
    • 问题解决
    • 本文总结

前言

本文主要是演练java应用频繁full gc,oom,如何排查解决的过程

演练代码

线程池用自定义线程工厂

jvm参数:-Xms20M -Xmx20M -XX:+PrintGC -Xloggc:gc.log

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 从数据库中读取数据,套用特定模型处理(线程池处理),最后对处理结果进行记录和传输等操作
 */
public class FullGC_Problem01 {
    private static class CardInfo {
        BigDecimal price = new BigDecimal(0.0);
        String name = "张三";
        int age = 5;
        Date birthdate = new Date();

        public void m() {
            // log and transfer
        }
    }

    static class MyThreadFactory implements ThreadFactory {

        private AtomicInteger count = new AtomicInteger(0);

        @Override
        public Thread newThread(Runnable r) {
            Thread t = new Thread(r);
            String threadName = "ModelFitThread-" + count.addAndGet(1);
            System.out.println(threadName);
            t.setName(threadName);
            return t;
        }
    }

    private static ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(50,
            new MyThreadFactory(),
            new ThreadPoolExecutor.DiscardOldestPolicy());

    public static void main(String[] args) throws Exception {
        executor.setMaximumPoolSize(50);

        for (;;){
            modelFit();
            Thread.sleep(100);
        }
    }

    private static void modelFit(){
        List<CardInfo> taskList = getAllCardInfo();
        taskList.forEach(info -> {
            // do something
            executor.scheduleWithFixedDelay(() -> {
                //do sth with info
                info.m();

            }, 2, 3, TimeUnit.SECONDS);
        });
    }

    private static List<CardInfo> getAllCardInfo(){
        List<CardInfo> taskList = new ArrayList<>();

        for (int i = 0; i < 100; i++) {
            CardInfo ci = new CardInfo();
            taskList.add(ci);
        }

        return taskList;
    }
}

故障现象

  • CPU飙高(top命令可查,线上一般有CPU >60% >80%等告警)
  • gc log 观察有频繁full gc,且gc不了等现象
-Xms20M -Xmx20M -XX:+PrintGC -Xloggc:gc.log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=java_heapdump.hprof

jmap查看

  • jmap使用注意和常规操作
  1. 高可用下,下线某台实例,用该台机器jmap测试
  2. 流量打到测试机,然后操作
  3. 堆转储文件:-XX:+HeapDumpOnOutOfMemoryError
  • jmap查看占用内存多的
mubi@mubideMacBook-Pro ~ $ jmap -histo 15840 | head -20

 num     #instances         #bytes  class name
----------------------------------------------
   1:         47300        3405600  java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask
   2:           887        2879080  [I
   3:         83270        2664640  java.util.concurrent.locks.AbstractQueuedSynchronizer$Node
   4:         47326        1893040  java.math.BigDecimal
   5:         47300        1513600  FullGC_Problem01$CardInfo
   6:         47300        1135200  java.util.Date
   7:         47300        1135200  java.util.concurrent.Executors$RunnableAdapter
   8:         47300         756800  FullGC_Problem01$$Lambda$2/245257410
   9:             3         444216  [Ljava.util.concurrent.RunnableScheduledFuture;
  10:          2528         368872  [Ljava.lang.Object;
  11:          2276         307064  [C
  12:           748          85680  java.lang.Class
  13:          2264          54336  java.lang.String
  14:            42          26080  [B
  15:            57          21432  java.lang.Thread
  16:           185          13320  java.lang.reflect.Field
  17:           147          12936  java.lang.reflect.Method

问题原因定位

  • taskList 一直被executor所引用,无法释放(有内存泄漏

ScheduledThreadPoolExecutor scheduleWithFixedDelay(每隔多少时间,固定执行任务)定时任务一直要引用taskList , 即executor不被gc掉,其引用taskList也不会被gc掉

不断的内存泄漏,引发最后的内存溢出,即出现频繁Full gc, 但 gc不了,最后有OOM问题

问题解决

换个线程池,或者直接execute就行了,如下(即解决下内存泄漏)

private static void modelFit(){
       List<CardInfo> taskList = getAllCardInfo();
       taskList.forEach(info -> {
           // do something
           executor.execute(() -> {
               //do sth with info
               info.m();

           });
       });
   }

本地用jvisualvm观察如下

本文总结

【演练代码】本文参考了网上的;分析其实就是把平时的jvm问题排查相关的命令用起来,以及对相关的机器指标等关注

本文地址:https://blog.csdn.net/qq_26437925/article/details/107372031

《【演练】Java应用频繁Full GC, OOM.doc》

下载本文的Word格式文档,以方便收藏与打印。