内存泄漏 的 造成原因 及 解决方案
-
对象内存过大
- 保存占大量内存的对象,如Bitmap, XML文件
-
资源没及时释放
- context, Cursor, IO的引用没有及时释放
-
static关键字问题
- static 是java的关键字,当修饰该关键字的成员变量就不再属于对象,而是属于类变量,生命周期延长,如果用static来修饰引用资源过多的实例,如context的时候就容易出现内存泄漏
- 解决办法
- 避免static 成员变量引用耗费资源的实例,如context
- context尽量使用ApplicationContext, 因为Application的Context的生命周期较长,引用不会出现内存泄漏问题
- 使用WeakReference代替强引用:WeakReference<Context> mContextRef;
-
线程导致内存溢出
public class MyActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); new MyThread().start(); } private class MyThread extends Thread{ @Override public void run() { super.run(); //do somthing while(true) } } }
假设MyThread是一个耗时操作,当切换横竖屏的时候,会重新调用Activity的生命周期方法,销毁旧的Activity。但是由于MyThread中保存了Activity的引用,所以老的Activity并不会被销毁,从而出现了内存泄漏
AsyncTask问题更加严重,AsyncTask 内部的实现机制是运用了ThreadPoolExcutor,该类产生的Thread 对象的生命周期是不确定的,是应用程序无法控制的,因此如果AsyncTask 作为Activity 的内部类,就更容易出现内存泄露的问题。
解决办法:
- 将线程的内部类,改为静态内部类(因为非静态内部类拥有外部类对象的强引用,而静态类则不拥有)。
- 在线程内部采用弱引用保存Context 引用
内存溢出 的 造成原因 及 解决方案
-
图片过大导致OOM
- Android 中用bitmap 时很容易内存溢出,比如报如下错误:Java.lang.OutOfMemoryError : bitmap size
exceeds VM budget。 - 解决办法:
- 边界压缩 (等比例缩小图片) 图片: 只保存图片尺寸大小,不加载图片到内存:
Options options = new BitmapFactory.Options();
等比例缩小图片(缩小比例需要计算):opts.inSampleSize = 2;
- 软引用:
SoftReference<Bitmap> bitmap = new SoftReference<Bitmap>(Bitmap);
- 及时回收:
bitmap.get().recycle();
- 边界压缩 (等比例缩小图片) 图片: 只保存图片尺寸大小,不加载图片到内存:
- Android 中用bitmap 时很容易内存溢出,比如报如下错误:Java.lang.OutOfMemoryError : bitmap size
-
界面切换导致OOM
- 横竖屏切换N 次后OOM 了
- 解决办法:
- 页面布局的背景图改成到activity的onCreate中设置。在activity的destroy方法中进行释放
drawable.setCallback(null);
- 在页面切换时尽可能少地重复调用数据库,反复使用某些对象等
- 在onPause()、onStop()、onDestroy()方法中适当的释放资源
- 页面布局的背景图改成到activity的onCreate中设置。在activity的destroy方法中进行释放
-
数据库的Cursor没有及时关闭
-
构造Adapter 时,没有使用缓存的convertView
Android 中如何捕获没法打印的app崩溃异常
自定义一个Application,继承Application 实现UncaughtExceptionHandler
覆写UncaughtExceptionHandler 的onCreate 和uncaughtException 方法
@Override
public void onCreate() {
super.onCreate();
Thread.setDefaultUncaughtExceptionHandler(this);
}
@Override
public void uncaughtException(final Thread thread, final Throwable ex) {
new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();
System.out.println(Thread.currentThread());
Toast.makeText(getApplicationContext(), "thread="+thread.getId()+"ex="+ex.toString(), 1).show();
Looper.loop();
// 保存异常信息到手机sd卡中,上传服务器
}
}).start();
SystemClock.sleep(3000);
android.os.Process.killProcess(android.os.Process.myPid());
}
网友评论