Android 常见内存泄漏

内存泄漏(Menory Leak)

进程中某些对象已经没有使用价值,但是他们却还是直接或间接地被引用到GC Root导致无法回收。

内存溢出(OOM)

当内存泄漏过多时,再加上应用本身占有的内存,日积月累最终就会导致内存溢出。

专业说法: 当应用占用的heap资源超过了虚拟机分配的内存就会内存溢出,比如加载大图片。

内存泄漏的影响

  • 应用卡顿
    • 泄漏的内存影响GC的内存分配,过多的内存泄漏会影响应用的执行效率
  • 应用异常(OOM)
    • 过多的内存泄漏,最终导致虚拟机可分配的内存越来越少,更加容易出现OOM
1. 静态变量、单例引用Activity和View

一直持有着Activity、View的引用,导致Activity无法被释放。静态变量、单例的Context不要传入Activity。

public class MainActivity extends AppCompatActivity {

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

        SingleTon.getInstance(this); //错误
        SingleTon.getInstance(getApplication()()); //正确
    }
}
2. 非静态内部类(包括匿名内部类)

在java中,非静态内部类会隐式持有外部类,如果内部类没有被释放,那么外部类也不会被释放。
所以内部类应该使用static,这样可以避免内部类隐式持有外部类。

public class MainActivity extends AppCompatActivity {

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

    public void show(String message) {
        Toast.makeText(MainActivity.this, message, Toast.LENGTH_SHORT).show();
    }

    static class Inner {
        private Reference<MainActivity> activityRef;

        public Inner(MainActivity activity) {
            this.activityRef = new WeakReference(activity);
        }

        public void method1() {
            MainActivity activity = this.activityRef.get();
            if (activity == null) {
                return; //activity为null说明activity已经被回收了
            }

            //调用activity
            activity.show("hello world!");
        }
    }
}

比如Handler等,应使用静态内部类。

(2). 匿名内部类
匿名内部类对外部类都持有一个隐式引用。
比如AsyncTask和Thread,如果在Activity销毁前,任务还未完成,那么将导致Activity的内存资源无法回收,造成内存泄漏。

public class MainActivity extends AppCompatActivity {

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

        new Thread() {
            @Override
            public void run() {
                SystemClock.sleep(100 * 10);
            }
        }.start();
    }
}

应该使用静态内部类来解决

3. 不需要的监听未移除

注册的监听需要在不使用的时候注销

(1).自己的监听

public class ThirdActivity extends AppCompatActivity 
implements NotifyController.UpdateCallback {

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

        NotifyController.registerCallback(this);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        //结束时应移除监听
        NotifyController.unregisterCallback(this);
    }
}

(2).系统的监听-示例1

SensorManager sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
Sensor sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ALL);
sensorManager.registerListener(this, SensorManager.SENSOR_DELAY_FASTEST);  

//不用的时候,需要取消监听
sensorManager.unregisterListener(this);

(3).系统的监听-示例2

getWindow().getDecorView().getViewTreeObserver().addOnWindowFocusChangeListener(new ViewTreeObserver.OnWindowFocusChangeListener() {
    @Override
    public void onWindowFocusChanged(boolean b) {
        //监听VIew的加载,View加载出来的时候,计算他的宽高
    }
});

//不用的时候,需要取消监听
getWindow().getDecorView().getViewTreeObserver().removeOnWindowFocusChangeListener(this);
4.资源未关闭

对于使用BroadcastReceiver、ContentObserver、File、Cursor、Stream、Bitmap等资源的使用,应该在Activity销毁时及时关闭或者注销,否则这些资源将不会回收,造成内存泄漏。

Bitmap的回收

5. 无限循环动画

如果动画时无限循环的,记得要在Activity结束时,将其停止。

其他

参考
Android性能优化-内存泄漏的8个Case
Android 内存泄漏分析
Android开发必备技能:关于你所不知道的内存管理
Android OOM案例分析

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

氦客

你的鼓励是我创作最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值