【演练】Java应用频繁Full GC, OOM
程序员文章站
2022-05-14 20:42:10
目录前言演练代码故障现象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使用注意和常规操作
- 高可用下,下线某台实例,用该台机器jmap测试
- 流量打到测试机,然后操作
- 堆转储文件:
-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