`

两个OOM Cases排查过程的分享

阅读更多

分享一下两个OOM Cases的查找过程,一个应用是Native OOM;另外一个应用其实没有OOM,只是每隔一段时间就会出现频繁FGC的现象,OOM的查找已经具备了不错的工具,但有些时候还是会出现很难查的现象,希望这两个排查过程的分享能给需要的同学带来一些帮助。

Native OOM的排查Case
之前的几个PPT里我都说到了,目前查找Native OOM最好的方法就是用google perftools了,于是挂上google perftools,等待应用再次native oom,很幸运,两天后,应用就再次native oom了,于是分析crash之前那段时间谁在不断的分配堆外的内存,pprof看到的结果主要是java.util.Inflater造成的,由于之前已经碰到过类似的case,知道如果使用了Inflater,但不显式的调用Inflater.end的话,确实会造成这个现象。
于是剩下的问题就是找出代码里什么地方调用了Inflater,这种时候btrace这个神器就可以发挥作用了,一个简单的btrace脚本:

import static com.sun.btrace.BTraceUtils.*;
import com.sun.btrace.annotations.*;
  
@BTrace public class Trace{
   @OnMethod(
      clazz="java.util.zip.Inflater",
      method="/.*/"
   )
   public static void traceExecute(@ProbeMethodName String methodName){
     println(concat("who call Inflater.",methodName));
     jstack();
   }
}

执行后很快就找到了代码什么地方调用了Inflater,于是加上了显式的调用Inflater.end,搞定收工。

偶尔频繁FGC的排查Case
这个Case就没上面的那个那么顺利了,查了有接近一个月才查出最终的原因。
当这个应用出现频繁FGC时,dump了内存,用MAT分析后,看到内存被消耗完的原因是由于几个线程内的ThreadLocalMap中有大量的数据,ThreadLocal中消耗最多内存的主要是一个HashMap,这里面有大量的数据。
于是当时想到的第一个方法就是查查应用里面什么地方往ThreadLocal里放了HashMap,杯具的是,当查找代码后发现应用本身的代码并没有往 ThreadLocal里放HashMap,那就只能是应用依赖的其他jar包做了这样的事了,但不可能去抓出这个应用依赖的所有的jar的源码来扫描,于是继续借助BTrace,写了个脚本来跟踪这类型的线程中谁调用了ThreadLocal.set,并且放的是HashMap,btrace脚本如下:

import static com.sun.btrace.BTraceUtils.*;
import com.sun.btrace.annotations.*;
  
@BTrace public class Trace{
   @OnMethod(
      clazz="java.lang.ThreadLocal",
      method="set"
   )
   public static void traceExecute(Object value){
      if(startsWith(name(currentThread()),"xxx") && startsWith("java.util.HashMap",name(classOf(value))) ){
           println("-------------------------");
           jstack();
           println();
      }
   }
}

OK,开始运行上面的脚本,发现竟然一直都没打印出什么内容,只能一直等了,杯具的是一直到了一周后再次出现频繁FGC时,这个脚本都没输出任何的东西,于是只好转换思路。

既然是HashMap里put了大量的某种类型的数据,那干脆用btrace来看看是谁在往HashMap里put这些数据,于是又写了一个 btrace脚本,执行后,很快就看到了是代码中什么地方在put这些数据,但是从抓到的调用者来看,不仅仅是目前有大量数据的这类型的线程会调,其他类型的线程也会调用,如果这个地方有问题的话,应该就全部有问题了,于是跳过这里。

回到MAT看到的现象,会不会是因为代码什么地方用ThreadLocal的方式不对,又或是什么地方往ThreadLocal里放了东西,又忘了清除呢,因此要做的就是找出这个应用中所有属性为ThreadLocal的地方,来人肉分析了,于是写了一个jsp,扫描所有的classloader中的所有class,找出属性类型为ThreadLocal的,扫描后找到了一些,还真发现有一个和现在HashMap中放的数据一样的private ThreadLocal,这种用法在线程复用的情况下,如果是每次new ThreadLocal的话,会导致ThreadLocal放的东西一直不释放,兴奋的以为已经发现原因了,可惜和业务方一确认,这个类借助Spring 保证了singleton的,因此不会有问题。
好吧,到这一步,只能猜想是由于某种参数请求的时候造成业务上会获得大量的数据了,于是想着要找业务方来分析代码了,这个非常麻烦,于是到此就几乎停滞不前了。

今天静下心来,重新仔细的看了下MAT分析的结果,决定仍然用btrace跟踪下之前往HashMap中put数据的那个业务代码,突然发现,在 web类型的处理线程中它借助的是filter去clear数据的,而杯具的是出问题的这种类型线程的处理机制是没有filter机制的,因此猜测问题估计出在这里了,继续btrace,看看这种类型的线程中是不是只有人调put,没人调clear,btrace脚本运行,很快就验证了这个猜测,于是相应的解决掉了这个case,搞定收工。

在这第二个case中,可见在频繁FGC或者OOM时,很有可能MAT只能告诉你初步的原因,但要对应到代码上到底是什么地方造成的,还得花很大精力分析了,这个时候BTrace通常能帮上很大的忙。

 

 

文章转载自:http://rdc.taobao.com/team/jm/archives/684

分享到:
评论

相关推荐

    一次OOM问题排查过程实战记录

    OOM 问题排查过程实战记录 一、OOM 问题排查过程概述 在 Java 应用程序中,OutOfMemoryError 是一种常见的异常,它可能是由于堆空间不足、永久代空间不足或是无法分配对象所引发的。在本文中,我们将通过一个实战...

    JVM堆内存分析工具,OOM排查工具。包括ha和mat两种

    在Java虚拟机(JVM)的运行环境中,内存管理是至关重要的一个环节,尤其是在大型应用或者高并发场景下。当程序出现性能问题或者"OutOfMemoryError"(OOM)时,理解堆内存的使用情况就显得尤为关键。"JVM堆内存分析...

    MySQL OOM(内存溢出)的解决思路

    内存溢出产生原因多种多样,当内存严重不足时,内核有两种选择: 直接panic 杀掉部分进程,释放一些内核。 大部分情况下,会杀掉导致OOM的进程,然后系统恢复。通常我们会添加对内存的监控报警,例如:当memory或...

    OOM小例子,用于验证oom出现以及对应的问题排查

    本篇将通过一个简单的OOM例子来探讨这个问题的发生原因、如何复现以及如何进行问题排查。 一、OOM现象与原因 当Java应用出现OOM时,JVM会抛出`java.lang.OutOfMemoryError`异常。这通常由以下几种情况引起: 1. *...

    OOM分析工具-MemoryAnalyzer.zip

    4. **comparison 视图**:如果你有两个或多个heap dump文件,可以使用此视图来比较它们之间的差异,找出内存占用增加的来源。 5. **shallow 和 retained size**:MAT区分了对象的浅层大小(shallow size)和保留...

    oom技术分享,各种情况下可能会出现的oom事故

    java jvm 中关于内存溢出分享,举例说明各种情况下可能会出现的oom事故

    一个线程oom会影响其他线程吗1

    这两个资源是线程私有的。其他资源,如堆、地址空间、全局变量,则是由同一个进程内的多个线程共享的。特别是堆,它是线程共享的资源。 测试代码 为了验证一个线程抛出 OOM 异常是否会影响其他线程的运行,我们...

    有关OOM KILLER的一些理解

    它调用之前两个模块的结果,最终决定并终止某个进程,同时记录相关日志,帮助后续分析。 理解OOM Killer的工作原理对于优化系统性能和调试内存问题至关重要。例如,开发者可以通过调整oom_score_adj值来影响某个...

    图片oom,解决方法

    在Android开发中,"图片OOM"是一个常见的问题,全称为"Out Of Memory",即内存溢出异常。当应用程序在运行过程中,分配给它的内存不足以处理当前的操作时,就会发生这种异常。尤其在处理大量或者高分辨率的图片时,...

    GridView解决OOM

    OOM是Java编程语言中的一个异常,当应用程序请求的内存超过了系统分配的最大值,系统无法满足其需求时就会抛出此异常。在Android中,尤其是处理大量图片时,如果不合理地管理内存,非常容易触发OOM。 **GridView与...

    Android OOM错误的原因

    在Android开发过程中,经常会遇到一种常见的异常——OutOfMemoryError(简称OOM),这主要是因为Android为了确保设备性能与响应速度,在内存管理方面设定了严格的限制。对于每个应用程序进程,默认情况下只能使用...

    android解决OOM

    在Android开发中,"OOM"(Out of Memory)是一个常见的问题,它指的是应用程序在运行过程中耗尽了可用的内存,导致系统无法分配更多的内存资源,从而引发崩溃。为了解决这个问题,开发者需要深入理解Android内存管理...

    bitmap OOM的解决方案

    Android系统为每个应用程序分配一定的内存预算,当这个预算被超出时,就会抛出OOM异常。不同设备的内存预算不同,因此开发者需要确保Bitmap的使用不会过度消耗内存。 解决Bitmap OOM问题的方法多种多样: 1. **...

    处理android bitmap oom

    在Android开发中,Bitmap对象是用于处理图像的主要类,但如果不妥善管理,它可能会引发“Out Of Memory”(OOM)错误。...记住,每个应用都有其特定的内存限制,理解并适应这些限制是成功避免OOM的关键。

    安卓gif加载解决oom

    Android系统为每个应用分配一定的内存预算,当应用超过这个预算时,就会抛出OOM异常。对于大内存消耗的资源,如高分辨率的图片或动态图,不合理的加载和缓存策略可能导致内存快速膨胀。 1. **使用高效的GIF库**:...

    gif加载动画不oom

    在测试过程中,开发者应使用Android Studio的内存分析工具(Memory Profiler)进行内存泄漏检测和性能优化,确保代码在不同设备和使用场景下都能稳定运行。同时,持续关注社区更新,及时引入新的优化方案,以保持...

    Spark面对OOM问题的解决方法及优化总结1

    在Spark运行过程中,内存溢出(OOM)问题可能导致任务失败,影响整个应用程序的效率。本篇文章主要探讨Spark面对OOM问题的解决方法及优化策略。 首先,我们需要了解Spark的内存模型。Spark的Executor内存分为三个...

    自定义相册实现多选照片解决oom

    然而,实现这样一个自定义相册并处理多选照片的过程中,常常会遇到内存溢出(Out Of Memory,简称OOM)的问题。本文将详细探讨如何通过自定义相册来实现多选照片功能,并针对OOM问题提出解决方案。 首先,自定义...

    加载图片oom的解决

    在Android开发中,由于系统对每个应用程序分配的内存有限,加载大尺寸的图片可能会导致“Out Of Memory”(OOM)异常,从而影响应用的稳定性和性能。为了解决这个问题,我们需要掌握一些有效的策略来优化图片加载,...

Global site tag (gtag.js) - Google Analytics