一次惊心动魄的线上事故:记一次内存泄漏Bug的排查与解决全过程

发布于:2025-09-05 ⋅ 阅读:(16) ⋅ 点赞:(0)

前言

大家好,今天想和大家分享一个我接手外包项目时遇到的严重性能问题。这个问题排查过程异常曲折,整整花了3天时间才定位到根本原因。通过这次经历,我对OkHttp的连接池机制有了更深刻的理解,也意识到代码规范的重要性。

问题背景

我们接手了一个外包团队开发的直播类App,接手后测试发现一个奇怪的问题:只有华为手机在使用某个直播页面时会出现OOM(Out Of Memory)错误,其他品牌手机完全正常。

最初我们错误地认为这是华为机型的适配问题,但深入分析后发现问题的根源完全不同。

问题现象

  1. 机型差异:只有华为手机出现OOM,其他品牌手机正常
  2. 偶发性:问题不是必现,需要反复打开关闭直播页面多次才会触发
  3. 内存异常:OOM错误堆栈显示线程创建失败,暗示线程数过多

错误日志大致如下:

java.lang.OutOfMemoryError: pthread_create (1040KB stack) failed: Out of memory
    at java.lang.Thread.nativeCreate(Native Method)
    at java.lang.Thread.start(Thread.java:733)
    at java.util.concurrent.ThreadPoolExecutor.addWorker(ThreadPoolExecutor.java:975)
    at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1393)
    ...

排查过程

第一步:初步分析

看到OOM错误,我们首先想到的是内存泄漏,于是集成了LeakCanary进行监控,但没有发现明显的内存泄漏报告。这让我们意识到问题可能不是传统的内存泄漏。

第二步:使用Android Studio Profiler

我们使用AS Profiler监控应用运行状态,发现了一个惊人的现象:

每次打开直播页面,线程数量都会显著增加,而且在页面关闭后线程并没有被回收。反复操作几次后,线程数从正常的几十个增长到300多个,最终导致OOM。

第三步:分析页面代码

我们仔细分析直播页面的代码,发现页面中确实有很多网络请求,但奇怪的是其他页面也有网络请求,为什么只有这个页面有问题?

通过分析发现:

  1. 该页面确实比其他页面请求的接口多
  2. 反复打开页面时,线程数持续增长
  3. 页面关闭时,网络请求没有被正确取消

第四步:检查网络请求框架

项目使用的是Retrofit + OkHttp的经典组合。我们发现Retrofit确实是单例的,但问题出在OkHttpClient上。

通过断点调试,我们发现了一个严重问题:

虽然Retrofit是单例,但每次网络请求时都创建了新的OkHttpClient实例,导致连接池配置失效!

问题代码如下:

// 外包团队的错误实现
public class ApiManager {
   
   
    private static volatile Retrofit retrofit;
    
    public static ApiService getApiService() {
   
   
        if (retrofit == null) {
   
   
            synchronized (ApiManager.class) {
   
   
                if (retrofit == null) {
   
   
                    retrofit = new Retrofit.Builder()
                        .baseUrl(BASE_URL)
                        .

网站公告

今日签到

点亮在社区的每一天
去签到