Android常见内存泄漏及优化的学习笔记

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wj610671226/article/details/89110849

Android常见内存泄漏及优化的学习笔记

  • 单例导致的内存泄漏
public class AppSettings {
    private static AppSettings sInstance; private Context mContext;
    private AppSettings(Context context) { 
        // 错误代码
        this.mContext = context;
        // 正确代码
        this.mContext = context.getApplicationContext();
    }
    public static AppSettings getInstance(Context context) { 
        if (sInstance == null) {
            sInstance = new AppSettings(context); 
        }
        return sInstance; 
    }
}

说明:如果AppSettings的getInstance传入的context是Activity、Service的上下文就会导致内存泄漏(当我们退出 Activity 时,该 Activity 就没有用了,但是因为 sIntance 作为静态单例(在应用程序的整个生命周期中存在)会继续持有这个 Activity 的引用,导致这个 Activity 对象无法被回收释放,这就造成了内存泄露。)。

  • 静态变量导致的内存泄漏
public class MainActivity extends Activity {
    private static Info info;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);   
        setContentView(R.layout.activity_main); 
        if (info != null) {
            info = new Info(this); 
        }
    } 
}
class Info {
    public Info(Activity activity) { }
}

说明:Info作为Activity的静态成员,并且持有Activity的引用,所以当Activity退出后,info仍然引用了Activity,Activity不能被回收,这就导致了内存泄露.
解决办法:在不使用或者适当的时候把info重置为null.

  • 非静态内部类导致内存泄漏

非静态内部类(包括匿名内部类)默认就会持有外部类的引用(静态内部类不会),当非静态内部类对象的生命周期 比外部类对象的生命周期长时,就会导致内存泄露。

类似场景:
1、Handler使用
2、在Activity中直接使用Thread或者AsyncTask内部类

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);     
        setContentView(R.layout.activity_main); 
        start();
    }
    private void start() {
        Message msg = Message.obtain();
        msg.what = 1;
        mHandler.sendMessage(msg);
    }
    private Handler mHandler = new Handler() { 
        @Override
        public void handleMessage(Message msg) { } 
    };
}
// 造成内存泄漏的原因:message->handler->activity
// 解决办法:采用静态内部类+弱引用的方式
public class MainActivity extends AppCompatActivity {
    private Handler mHandler;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);     
        setContentView(R.layout.activity_main); 
        mHandler = new MyHandler(this); 
        start();       
    }
    private void start() {
        Message msg = Message.obtain();
        msg.what = 1;
        mHandler.sendMessage(msg);
    }
    @Override
    protected void onDestroy() { 
        super.onDestroy(); 
        mHandler.removeCallbacksAndMessages(null);
    }
   private static class MyHandler extends Handler {
        private WeakReference<MainActivity> activityWeakReference;
        public MyHandler(MainActivity activity) { 
            activityWeakReference = new WeakReference<>(activity);
        }
        @Override
        public void handleMessage(Message msg) {
            MainActivity activity = activityWeakReference.get();
            if (activity != null) {}
        } 
    }
}
  • 其他问题导致的内存泄漏

1、未取消注册或者回调导致内存泄漏(广播)
2、Timer和TimerTask导致内存泄漏
3、集合中的对象未清理造成内存泄漏
如果一个对象放入到 ArrayList、HashMap 等集合中,这个集合就会持有该对象 的引用。当我们不再需要这个对象时,也并没有将它从集合中移除,这样只要集合还在使用(而 此对象已经无用了),这个对象就造成了内存泄露。并且如果集合被静态引用的话,集合里面那 些没有用的对象更会造成内存泄露了。所以在使用集合时要及时将不用的对象从集合 remove,或 者 clear 集合,以避免内存泄漏。
4、资源未关闭或释放导致内存泄漏
在使用 IO、File 流或者 Sqlite、Cursor 等资源时要及时关闭。这些资源在进行读写操作时通常都 使用了缓冲,如果及时不关闭,这些缓冲对象就会一直被占用而得不到释放,以致发生内存泄露。 因此我们在不需要使用它们的时候就及时关闭,以便缓冲能及时得到释放,从而避免内存泄露
5、属性动画造成内存泄漏
动画同样是一个耗时任务,比如在 Activity 中启动了属性动画(ObjectAnimator),但是在销毁 的时候,没有调用 cancle 方法,虽然我们看不到动画了,但是这个动画依然会不断地播放下去, 动画引用所在的控件,所在的控件引用 Activity,这就造成 Activity 无法正常释放。因此同样要 在 Activity 销毁的时候 cancel 掉属性动画,避免发生内存泄漏。
6、WebView造成内存泄漏
关于 WebView 的内存泄露,因为 WebView 在加载网页后会长期占用内存而不能被释放,因此我 们在 Activity 销毁后要调用它的 destory()方法来销毁它以释放内存。

猜你喜欢

转载自blog.csdn.net/wj610671226/article/details/89110849