返回

一次 Android 线上 OOM 的排查过程

Android

一天,后台统计到线上有大量 OOM 崩溃,小王收到老板的紧急指令,立即排查!小王心想,这还不简单,待我看看崩溃堆栈,分分钟解决。于是小王不慌不忙的打开崩溃后台,一看傻眼了…

令人头疼的崩溃堆栈

映入小王眼帘的是一串晦涩难懂的崩溃堆栈,没有任何有价值的信息。小王挠了挠头,心想,这可咋整?这堆栈压根看不出问题啊!

无奈之下,小王只好硬着头皮开始分析。他仔细查看了崩溃堆栈中的每一行,试图找出蛛丝马迹。终于,他在崩溃堆栈的最后几行发现了一条线索:

at java.lang.Daemons$FinalizerDaemon.run(Daemons.java:201)

这条堆栈信息表明,OOM 崩溃是由垃圾回收器中的“终止器守护线程”(FinalizerDaemon)引发的。这给了小王一个新的思路,他决定从垃圾回收的角度入手进行排查。

MAT 工具助攻

小王打开 MAT(Memory Analyzer Tool)工具,导入线上崩溃时的堆转储文件。经过一番分析,小王发现了一个惊人的事实:堆中存在大量的未引用的 Bitmap 对象。

Bitmap 是 Android 中用来处理图像的类。在 Android 开发中,Bitmap 对象需要手动释放,否则就会导致内存泄漏。小王推测,线上 OOM 崩溃的原因就是由于未释放的 Bitmap 对象过多导致的。

代码审查

为了进一步确认自己的推测,小王对线上代码进行了仔细审查。经过一番搜索,他发现了一个潜在的问题点:

private Bitmap mBitmap;

public void onCreate(Bundle savedInstanceState) {
    ...
    mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.my_image);
    ...
}

public void onDestroy() {
    ...
    // 未释放 Bitmap 对象
}

在这个代码片段中,小王在 onCreate() 方法中创建了 Bitmap 对象,但在 onDestroy() 方法中却忘记释放它了。这会导致 Bitmap 对象无法被垃圾回收器及时回收,从而造成内存泄漏。

解决方案

为了解决 OOM 崩溃问题,小王对代码进行了修改,在 onDestroy() 方法中添加了释放 Bitmap 对象的代码:

public void onDestroy() {
    ...
    if (mBitmap != null) {
        mBitmap.recycle();
        mBitmap = null;
    }
}

经过修改后,小王重新编译并部署了代码。经过一段时间的观察,线上 OOM 崩溃的数量大幅下降。至此,这场 OOM 排查之战终于告一段落。

总结

通过这次 OOM 排查过程,小王总结出了以下经验教训:

  • 重视崩溃堆栈分析: 崩溃堆栈是 OOM 排查的重要线索,切勿忽视。
  • 善用 MAT 工具: MAT 工具可以帮助分析堆转储文件,找出内存泄漏的根源。
  • 仔细审查代码: OOM 崩溃往往是由代码中的内存泄漏造成的,因此仔细审查代码至关重要。
  • 及时释放资源: Android 中的 Bitmap 等资源需要手动释放,否则会导致内存泄漏。
  • 持续监控线上稳定性: 及时发现和解决线上问题,是保证服务稳定性的关键。