不要在主线程中处理图片
使用Bitmap对象要用recycle释放
// Bitmap对象没有被回收
if (!bitmapObject.isRecyled()) {
// 释放
bitmapObject.recycle();
// 提醒系统及时回收
System.gc();
}
控制图片的大小,压缩大图,高效处理,加载合适属性的图片。
当我们有些场景是可以显示缩略图的时候,就不要调用网络请求加载大图,例如在RecyclerView中,我们在上下滑动的时候,就不要去调用网络请求,当监听到滑动结束的时候,才去加载大图,以免上下滑动的时候产生卡顿现象。
建议使用第三方,或者JNI来进行处理
对于使用了BraodcastReceiver,ContentObserver,Cursor,File,Stream,ContentProvider,Bitmap,动画,I/O,数据库,网络的连接等资源的使用,应该在Activity销毁时及时关闭或者注销,否则这些资源将不会被回收,造成内存泄漏。
广播BraodcastReceiver:记得注销注册unregisterReceiver();
文件流File:记得关闭流InputStream / OutputStream.close();
数据库游标Cursor:使用后关闭游标cursor.close();
对于图片资源Bitmap:当它不再被使用时,应调用recycle()回收此对象的像素所占用的内存,再赋为null
动画:属性动画或循环动画,在Activity退出时需要停止动画。在属性动画中有一类无限循环动画,如果在Activity中播放这类动画并且在onDestroy中没有去停止动画,那么这个动画将会一直播放下去,这时候Activity会被View所持有,从而导致Activity无法被释放。在Activity中onDestroy去调用objectAnimator.cancel()来停止动画。
public class LeakActivity extends AppCompatActivity {
private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_leak);
textView = (TextView) findViewById(R.id.text_view);
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(textView, "rotation", 0, 360);
objectAnimator.setRepeatCount(ValueAnimator.INFINITE);
objectAnimator.start();
}
}
集合对象及时清理,使得JVM回收:我们通常会把对象存入集合中,当不使用时,清空集合,让相关对象不再被引用;
objectList.clear();
objectList=null;
严格的讲,String拼接只能归结到内存抖动中,因为产生的String副本能够被GC,不会造成内存泄露。
频繁的字符串拼接,使用StringBuffer或者StringBuilder代替String,可以在一定程度上避免OOM和内存抖动。
对于EventBus,RxJava等一些第三方开源框架的使用,若是在Activity销毁之前没有进行解除订阅将会导致内存泄漏
单例模式造成的内存泄漏,如context的使用,单例中传入的是activity的context,在关闭activity时,activity的内存无法被回收,因为单例持有activity的引用。
在context的使用上,应该传入application的context到单例模式中,这样就保证了单例的生命周期跟application的生命周期一样。
因为单例的静态特性使得单例的生命周期和应用的生命周期一样长,这就说明了如果一个对象已经不需要使用了,而单例对象还持有该对象的引用,那么这个对象将不能被正常回收,这就导致了内存泄漏。
单例模式应该尽量少持有生命周期不同的外部对象,一旦持有该对象的时候,必须在该对象的生命周期结束前null
public class TestManager {
private static TestManager instance;
private Context context;
private TestManager(Context context) {
this.context = context;
}
public static TestManager getInstance(Context context) {
if (instance != null) {
instance = new TestManager(context);
}
return instance;
}
}
这是一个普通的单例模式,当创建这个单例的时候,由于需要传入一个Context,所以这个Context的生命周期的长短至关重要:
1、传入的是Application的Context:这将没有任何问题,因为单例的生命周期和Application的一样长 ;
2、传入的是Activity的Context:当这个Context所对应的Activity退出时,由于该Context和Activity的生命周期一样长(Activity间接继承于Context),所以当前Activity退出时它的内存并不会被回收,因为单例对象持有该Activity的引用。
所以正确的单例应该修改为下面这种方式:
public class TestManager {
private static TestManager instance;
private Context context;
private TestManager(Context context) {
this.context = context.getApplicationContext();
}
public static TestManager getInstance(Context context) {
if (instance != null) {
instance = new TestManager(context);
}
return instance;
}
}
这样不管传入什么Context最终将使用Application的Context,而单例的生命周期和应用的一样长,这样就防止了内存泄漏。
在onPause()/onDestroy()方法中解除监听器,包括在Android自己的Listener,Location Service或Display Manager Service以及自己写的Listener。