总结Android中遇见的OOM
一 、Android应用中内存泄漏几种的原因:
1.单例模式导致的内存泄漏:
当调用getInstance时,如果传入的context是Activity的context。只要这个单例没有被释放,这个Activity的引用就不会被释放,从而导致OOM。
解决方法:
传入Application的context,因为Application的context和getInstance中的静态变量生命周期一样长,不会造 成当Activity销毁不掉。
2.内部类导致的内存泄漏:
我们在使用Thread或者广播接收器的时候经常会直接new Thread(),new MyBroadcastReceiver(),还有我们经常写的Handler都这样写都会造成内存泄漏。原因是我们这样写相当于创建了一个匿名内部类, 而内部类会隐士的持有一个外部类的引用不会释放,当Activity进行销毁的时候,就不会销毁,导致堆中存放着很多个Acitivity的引 用,又不会被GC掉。
解决办法:在Activity销毁时,尽可能将Acitivity的内部类引用进行销毁,注册广播的要及时的进行销毁,使用Handler的地方remove掉所有的Message 或者可以将内部类声明为静态类。但是将内部类声名为静态类后由于静态类不再持有外部类对象的引用,导致程序不允许内部类中操作 Activity中的对象了。所以需要在外部类中增加一个对Activity的弱引用(WeakReference),在创建内部类对象的时候将 Activity的引用传进去使用。
下面是以Handler为例使用静态类的代码:
static class MyHandler extends Handler {
WeakReference<Activity > mActivityReference;
MyHandler(Activity activity) {
mActivityReference= new WeakReference<Activity>(activity);
}
@Override
public void handleMessage(Message msg) {
final Activity activity = mActivityReference.get();
if (activity != null) {
mActivityReference.mImageView.setImageBitmap(mBitmap);
}
}
}
3.资源对象没关闭造成内存泄露
比如Cursor,File文件等我们在不使用的时候,应该及时关闭它们。否则多也会造成内存泄漏。
二、调试OOM的方法:
1.代码中添加严格模式。在程序运行时会将程序中潜在的危险信息以错误的形式打印出来。方法如下:
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
.detectLeakedSqlLiteObjects()
.detectAll()
.penaltyLog()
.build());
2.打印程序中每个对象的使用情况,进行分析内存泄露的原因。可以通过下面的命令将dump出堆中内存的使用情况,再Analyzer软件进行分析。
adb shell am dumpheap 程序的包名 /data/local/tmp/6.hprof
adb pull /data/local/tmp/6.hprof .
hprof-conv 6.hprof 6c.hprof
3.通过观察logcat中dalvikvm中GC的打印,如:
D/dalvikvm( 480): GC_CONCURRENT freed 1161K, 24% free 12700K/16568K, paused 6ms+6ms, total 60ms
如果内存回收打印情况一直在增多,则说明存在内存泄露。
4.通过adb shell 中的showmap观察内存的使用情况,看是否存在内存泄露。