Android OOM 攻略

对于程序员来讲,JAVA/Android遇到OOM绝对是让你头疼的问题,作为一名原本是C/C++程序员来说,我一开始觉得很诧异,说好的垃圾回收机制呢???你TM在逗我?

其实不是这样个说法,垃圾回收机制也是要靠你对引用的理解把握的,如果你对你的Activity已经释放完毕,但是你又使用了Activity.this,然后那个引用的变量还一直在,那么抱歉,你的Activity其实并没有释放,如同下面这个例子,首先定义一个单例类:

public class Test {
    public List<Context> list = new ArrayList<>();

    static Test sIns;
    public static Test getIns(){
        if(sIns == null){
            sIns = new Test();
        }
        return sIns;
    }
}

通过getIns()函数返回一个实例,假设我们定义了这样一个Main2Activity :

public class Main2Activity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);

        //10次是因为内存效果明显一点
        for(int i=0;i<10;i++)
            Test.getIns().list.add(this);
    }
}

每次创建都把自己加到单例里面的队列里面,问题就来了,退出这个Activity的时候,我们虽然执行了onDestory,但是很遗憾的是,我们的Main2Activity 并没有被回收,OK,内存泄露出来了。

上面只是一个简单的例子,平常我们在开发的时候并没有那么简单或者说不容易发现内存泄露。内存泄露并不一定是我们自己代码的问题,有可能你是从别人那边接手的代码。

下面进入正题,怎么对已经是烂摊子的代码快速定位到问题所在!
先介绍一个检测OOM隐患的代码辅助工具: leakcanary https://github.com/square/leakcanary

leakcanary的效果就是这样

我试了下,小Demo确实可以检测,问题是项目一大效果就没了,可能还需要再优化吧。具体怎么使用,同学们可以自己去看github上的说明。

下面我来介绍Android Studio的检测方法。
我是用的Android Studio版本是

这里写图片描述

我的项目目录是

这里写图片描述

MainActivity是启动Activity,有一个按钮可以到Main2Activity,Main2Activity和Test上面已经给出代码,这里给出MainActivity的

public class MainActivity extends AppCompatActivity {

   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_main);

       findViewById(R.id.tv).setOnClickListener(new View.OnClickListener() {
           @Override
           public void onClick(View view) {
               startActivity(new Intent(MainActivity.this,Main2Activity.class));
           }
       });
   }
}

启动调试,然后看下图,我们可以看到我们的App当前的运行内存!

这里写图片描述

然后我们点击MainActivity的按钮跳转到Main2Activity,再点物理键返回,重复多次后,我们的内存图片就这样了~~~

这里写图片描述

啊哦,从23.79M彪到27.48M了!!!
好吧,让我们来看看到底发生了什么,见下图操作:

这里写图片描述

第一步一定要多次点击,因为我们要排除干扰我们的因素,有些变量虽然占着内存,但是可以被GC回收的。
第二步完成后,AndroidStudio会自动打开一个.hprof的Java Heap信息文件

这里写图片描述

红色箭头解释:
1、是我们看抓取内容的目录
2、我们Dump Java Heap的具体文件
3、Class Name,我们内存中存在的Class都会在这个窗口
4、在这个Instance窗口我们可以看到某个类有哪几个实例
5、这个Reference Tree窗口,我们可以看到具体的引用树

完成以上介绍,那我们就可以开始查问题咯~~

上图那个3的红色箭头我故意指向了Class List View,那我们点击那个按钮,选择 Package Tree View

这里写图片描述

然后定位到我们自己的包名位置:

这里写图片描述

我的包名就是com.example.administrator.myapplication,这里我们很容易发现,我的Main2Activity类在内存中已经有31个实例了,那我们继续点一下它
这里写图片描述

可以很清楚的看到:右边的Instance窗口向我们展示了每个实例的内存地址,我们点击其中一个:

这里写图片描述

这时候Reference Tree 窗口告诉了我们引用关系,我们这个Main2Activity实例保存在Indices 的190到199的索引中,Indices 又是保存在array中,继续往下查找,我们找到了最后的保存位置,就是我们的Test的sIns中(红色箭头所指),其实就是sIns.list中。

好了,问题找到了,是我们的Test的sIns.list一直Hold了我们的Main2Activity,导致没有被GC回收,所以,我们在Main2Activity中增加代码:

@Override
protected void onDestroy() {
    super.onDestroy();

    //防止内存泄露
    for(int i=0;i<10;i++)
        Test.getIns().list.remove(this);

    //通知回收内存 - 并没什么卵用。。。
    //System.gc();
}

这时候不管我们点击几次,退回,再进去Main2Activity,我们的Main2Activity始终只有一个!!!

这里写图片描述

好了,打完收工!

千里之堤,溃于蚁穴。我们开发的时候需要多注意!

下面是我觉得应该在Android OOM开发方面应该注意的地方
1. 少用Activity的Context,除了必须要用的如Dialog等 可以使用 Application的Context
2. 对于用到的Context需要及时释放置为null
3. 线程的无节制使用也会耗尽内存,尽量使用 线程池Executors。
4. 对于占有内存较大的变量,我们需要在Activity销毁的时候把它置为null
5. 在一个Activity的基类上定义一个static final Handler,以后都用这个Handler,而不是无节制的new Handler
6. 对于一些经常用到的类,我们可以把它声明到Application中的静态变量,这样不会引发无节制的生成新的,占用空间
7. 对于一些需要单独创建的单列类,我们需要对其中引用到的的Context、View等大内存对象及时释放,不然内存会一泄千里

Android OOM(Out of Memory)是一种常见的运行时异常,指的是应用程序内存不足的错误。当应用程序试图使用超过系统分配给它的内存时,就会出现这种异常。这可能是由于应用程序在后台加载大量数据、存储过多的对象或图像,或者由于系统资源管理器分配的内存不足所致。 为了解决Android OOM问题,您可以采取以下几种策略: 1. 优化您的代码以减少内存使用量:使用正确的数据类型,避免创建不必要的对象,限制图像和资源的数量,以及优化后台加载过程等。 2. 回收不再使用的内存:当您的应用程序不再需要使用某些内存时,应该及时回收它们。这可以通过调用垃圾回收器(Garbage Collector)来完成。 3. 避免在主线程上执行耗时操作:如果您的应用程序在主线程上执行耗时操作(如大量数据处理),这可能导致系统资源管理器超载,从而引发OOM异常。应该将这些操作移至后台线程。 4. 使用内存分析工具:内存分析工具可以帮助您识别内存泄漏和无效内存引用等问题,从而避免OOM异常的发生。 5. 配置您的应用程序以适应不同的内存配置:如果您正在开发一个需要大量内存的应用程序,您应该考虑在AndroidManifest.xml文件中配置您的应用程序以适应不同的内存配置。例如,您可以设置您的应用程序需要的最低和最高内存限制。 请注意,解决Android OOM问题是一个复杂的过程,需要您仔细分析和优化您的代码。如果您遇到了OOM问题,建议寻求专业的帮助或与开发社区进行讨论。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值