当前位置: 首页 > 科技观察

Java服务,如何快速定位内存OOM问题?

时间:2023-03-12 20:09:54 科技观察

最近有朋友在知识星球上提问:沉老师,一个Java服务出现OOM(OutOfMemory)问题。我已经写好了,这里给出一些比较通用的解决方案,希望对Java技术栈的同学有所帮助。一个Java服务(假设PID=10765)发生了OOM。最常见的原因有:可能是内存分配确实太小了,正常业务使用内存比较多。一个对象频繁申请不释放,内存不断泄漏。导致内存耗尽频繁申请某项资源,导致系统资源耗尽,如:不断创建线程,不断发起网络连接画外音:无非是“资源不足”、“请求的资源太多”、疲惫”。更具体的,你可以使用以下工具来一一检查。1、确认内存本身是否分配太小方法:jmap-heap10765如上图,可以查看新生代和老年代堆内存的分配大小和使用情况,看是否是自己分配的太小。2、查找最耗内存的对象方法:jmap-histo:live10765|more如上图所示,输入命令后,会以表格的形式显示存活对象的信息,并根据排序theoccupiedmemorysize:实例数占用的内存大小类别,这个名字是不是很直观?对于实例数量多、占用内存大的实例/类,需要有针对性地审查相关代码。上图中占用内存最多的对象是RingBufferLogEvent,一共占用了18M内存,属于正常使用范围。如果发现某个类型的对象占用内存较大(比如好几个G),很可能是该类型的对象创建过多而没有释放。例如:申请资源后,没有调用close()或dispose()释放资源。消费者消费缓慢(或停止消费),而生产者不断向队列中发布任务,导致队列中的任务过多。画外音:Line执行这个命令会强制执行一个fgc。您还可以转储内存以供分析。3、确认是否资源耗尽的工具:pstreenetstat查看进程创建的线程数和网络连接数。如果资源耗尽,也可能会出现OOM。这里还有一个方法,通过/proc/${PID}/fd/proc/${PID}/task,可以分别查看句柄详情和线程数。比如线上服务器sshd进程的PID是9339,查看ll/proc/9339/fdll/proc/9339/task如上图,sshd占用四个句柄:0->标准输入1->standardOutput2->standarderroroutput3->socket(容易认为是监听端口)sshd只有一个PID为9339的主线程,没有多线程。所以,只要ll/proc/${PID}/fd|wc-lll/proc/${PID}/任务|wc-l(效果等同于pstree-p|wc-l)可以知道进程打开的句柄数和线程数。希望这1分钟能帮到这位星球水友。【本文为专栏作者《58神剑》原创稿件,转载请联系原作者】点此阅读更多该作者好文