Android内存泄漏常见场景

143 阅读2分钟

1.单例模式

public class AppManager {
    private static AppManager instance;
    private Context context;
    private AppManager(Context context) {
        this.context = context;
    }
    public static AppManager getInstance(Context context) {
        if (instance != null) {
            instance = new AppManager(context);
        }
        return instance;
    }
}

单例模式的静态特性使得实例的生命周期和Application一样长,如果某个对象的context传参构造单例模式,当对象不再使用而单例还持有该对象的引用不能被释放,导致内存泄漏。

解决办法:context用ApplicationContext

2.用非静态内部类创建静态实例

public class MainActivity extends AppCompatActivity {
    private static TestResource mResource = null;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        if(mResource == null){
            mResource = new TestResource();
        }
        //...
    }
    class TestResource {
    //...
    }
}

作用:防止重复创建资源。 泄漏原因:非静态内部类默认持有外部类的引用,静态实例与Application生命周期一样长 ,内部类使用完仍被静态实例持有,无法释放,Activity也无法释放,导致内存泄漏。

解决办法:每部类改为静态或者将内部类独立成为一个类以单例模式引用

3.Handler内存泄漏

public class MainActivity extends AppCompatActivity {
    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            //...
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        loadData();
    }
    private void loadData(){
        //...request
        Message message = Message.obtain();
        mHandler.sendMessage(message);
    }
}

Handler是非静态内部类,默认持有外部类引用,Activity结束时消息队列中消息没处理完,Message持有mHandler实例的引用,mHandler持有Activity的引用,导致Activity无法释放。

解决办法:创建Handler静态内部类,持有的对象使用弱引用

public class MainActivity extends AppCompatActivity {
    private MyHandler mHandler = new MyHandler(this);
    private TextView mTextView ;
    private static class MyHandler extends Handler {
        private WeakReference reference;
        public MyHandler(Context context) {
            reference = new WeakReference<>(context);
        }
        @Override
        public void handleMessage(Message msg) {
            MainActivity activity = (MainActivity) reference.get();
            if(activity != null){
            activity.mTextView.setText("");
            }
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mTextView = (TextView)findViewById(R.id.textview);
        loadData();
    }

    private void loadData() {
        //...request
        Message message = Message.obtain();
        mHandler.sendMessage(message);
    }
}

4.线程内存泄漏

异步任务和Runnable都是非静态内部类,默认持有外部类引用,Activity结束时异步任务没有结束导致不能释放内存。

解决办法:静态内部类

static class MyAsyncTask extends AsyncTask {
    private WeakReference weakReference;

    public MyAsyncTask(Context context) {
        weakReference = new WeakReference<>(context);
    }

    @Override
    protected Void doInBackground(Void... params) {
        SystemClock.sleep(10000);
        return null;
    }

    @Override
    protected void onPostExecute(Void aVoid) {
        super.onPostExecute(aVoid);
        MainActivity activity = (MainActivity) weakReference.get();
        if (activity != null) {
        //...
        }
    }
}
static class MyRunnable implements Runnable{
    @Override
    public void run() {
        SystemClock.sleep(10000);
    }
}
//——————
new Thread(new MyRunnable()).start();
new MyAsyncTask(this).execute();

5. 资源未关闭

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