欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2022-11-15 20:27:12
目录前言演练代码故障现象jmap查看问题原因定位问题解决本文总结前言本文主要是演练java应用频繁full gc,oom,如何排查解决的过程演练代码线程池用自定义线程工厂jvm参数:-Xms20M -Xmx20M -XX:+PrintGC -Xloggc:gc.logimport java.math.BigDecimal;import java.util.ArrayList;import java.util.Date;import java.util.List;import java.u...

前言

本文主要是演练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观察如下
【演练】Java应用频繁Full GC, OOM

本文总结

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

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