当前位置: 首页 > 后端技术 > Java

记一个Java内存存储异常排查流程

时间:2023-04-02 00:37:21 Java

1.现象java服务内存异常,占用服务器内存过多无法回收,存活到老年代2,再看gc日志,由于服务器一直在运行gc,所以很容易找到gc日志,使用gceasy.io快速查看gc日志情况,惊讶的发现newgeneration,oldgenerationgc回收一切正常,而且fullgc不频繁,oldgeneration正常回收,那为什么old世代这么大?3、目前开来堆正常,但是内存不断变大,于是把目光转向了堆外内存,于是用arthas观察堆外内存,但是发现directmemory和mapped都是内存正常,不是堆外内存泄漏。4.基本上可以确定不在堆里,但是眼睛还在堆外。后来找到了jcmd这个工具,但是需要重启服务,不敢乱用,但是发现jcmd的输出里面还有一个thread(reserved=159383KB,committed=159383KB)(thread#156)(stack:reserved=158720KB,committed=158720KB)(malloc=482KB#788)(arena=182KB#310)突然想到还没有检查服务线程的状态,于是用arthas看看,天哪,17000个线程5.基本可以肯定是线程创建过多导致的。查看大量线程的名字是pool-15000-thread-1,所以查了下日志才知道这个线程是做什么的。我发现了这样一段代码publicJSONObjectaaa(ListIds)throwsException{ExecutorServiceexecutorService=Executors.newFixedThreadPool(5);列表<未来>futureList=newArrayList<>();JSONObjectresultJson=newJSONObject();for(LongId:Ids){futureList.add(executorService.submit(newCallable(){@OverridepublicJSONArraycall()throwsException{returnbbb(Id);}}));}for(inti=0;ifuture=futureList.get(i);resultJson.put(Ids.get(i).toString(),future.get());}returnresultJson;}这是为了处理而创建的新线程池,会导致创建大量线程无法回收。3.反射应该使用公共线程池,而不是在使用的时候自己创建!!!