Android OOM

先通俗理解下内存泄漏,内存溢出,OOM,GC回收这几个概念。

内存溢出(out of memory) :

是指程序在申请内存时,没有足够的内存空间供其使用,出现out of memory(OOM)那就是内存溢出。内存溢出也就是内存不够用。

内存泄漏(memory leak) :

是指程序在申请内存后,无法释放已申请的内存;即本该被程序收回的对象不能被收回,继续停留在堆内存中;

把app的堆内存空间想成了一个杯子,内存就是里面的水。

当你的app启动后,系统会分配给app一个堆空间,起始不会很大比如是32M(根据你的app启动时的内存申请为准)

image

随着程序的运行对象的创建越来越多,系统不断加内存分配:32M -> 64M -> ...

而GC回收则会定时扫描内存,发现不被引用的对象即可回收。

正常来说你的app堆内存会有升有降。

此时如果有某个Activity持有某个引用,在onDestroy时还不把这个引用设为null,那么返回进入退出这个界面,Activity就会创建很多次从而存在多个实例,导致堆内存只升不降!这就叫做内存泄漏。

当用户重复这个操作或者有多个不同Activity内存泄漏时,app运行一段时间堆内存超过系统规定的最大值 heapSize,杯子满了就会发现内存溢出(OOM),app崩溃。

总结

内存溢出原因:

1.Android系统为每个应用程序申请到的内存有限,一般为16M或者24M 也有98M 221M等,我们可以在清单文件中进行配 置,android:largeheap = "true" 从而给APP申请更大的内存空间;

2.当应用程序产生的内存泄漏较多时,就会使程序所需要的内存超出系统分配的内存空间,导致内存溢出;

内存泄漏原因:

持有引用者的生命周期 > 被引用者的生命周期

1.资源对象没有关闭引起的内存泄漏

如:广播BraodcastReceiver、EventBus、文件流File、数据库游标Cursor、图片资源Bitmap、动画等,若在Activity销毁时没有调用相应的 类似close()、destroy()、recycler()、release()等方法释放则这些资源将不会被回收,从而造成内存泄漏
(1)广播BraodcastReceiver 记得注销注册unregisterReceiver();

(2)文件流File:记得关闭流InputStream / OutputStream.close();

(3) 数据库游标cursor:使用后关闭游标cursor.close();

(4) 对于 图片资源Bitmap:当它不再被使用时,应调用recycle()回收此对象的像素所占用的内存,再赋为null

    Bitmap.recycle();

    Bitmap = null;

(5) 动画:设置成无限循环播放repeatCount = “infinite”后,在Activity退出时记得停止动画

2.集合对象没有及时清理引起的内存溢出

我们通常会把对象存入集合中,当不使用时,记得清空集合,让相关对象不再被引用;

    objectList.clear();

    objectList=null;

3.Static 关键字修饰的成员变量 以及 单例模式

原因:static关键字修饰的成员变量(生命周期) = 应用程序(生命周期)

例如: 当Activity需销毁时,由于mContext的生命周期 = 应用程序的生命周期,则 Activity无法被回收,从而出现内存泄露

public class myactivity {
  // 定义1个静态变量
  private static Context mContext;
  // 引用的是Activity的context
  mContext = context; 
}

解决方法:如果使用Context ,尽可能使用Applicaiton的Context;

单例模式就是静态成员变量,所以在创建单例时,传入的Context最好是Applicaiton的Context;
例如:

单例模式

public class LoginManager {

    private Context context;
    private static LoginManager manager;

    public static LoginManager getInstance(Context context) {
        if (manager == null)
            manager = new LoginManager(context);
        return manager;
    }

    private LoginManager(Context context) {
        this.context = context;
    }
}

调用:

public class LoginActivity extends Activity  {

    private LoginManager loginManager;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);
        loginManager = LoginManager.getInstance(this);
    }
}

改为:

public class LoginManager {

    private Context context;
    private static LoginManager manager;

    public static LoginManager getInstance(Context context) {
        if (manager == null)
            manager = new LoginManager(context);
        return manager;
    }

    private LoginManager(Context context) {
        this.context = context.getApplicationContext();
    }
}

4.非静态内部类: [内部类探索]
(1)非静态内部类创建静态实例引起的内存泄漏

因为 静态实例的生命周期 = 应用程序的生命周期,所以非静态内部类生命周期 = 应用程序的生命周期;

因非静态内部类默认持有外部类的引用而导致外部类无法释放,从而导致内存溢出;

解决方法:将非静态内部类设置为静态内部类(因为静态内部类默认不持有外部类引用) 或者将该内部类抽取出来封装成一个单例;

(2)多线程: AsyncTask、实现Runnable接口、继承Thread类

多线程使用需要创建 非静态内部类 / 匿名内部类(运行时默认持有外部类引用)
原因: 线程正在处理任务,此时外部类需销毁,(线程实例生命周期 > 外部类生命周期)此时线程实例内部类持有外部类引用,使得外部类不能够被垃圾回收器回收,造成内存泄漏;

解决方法:将多线程实例类设置为静态内部类; 或者 当外部类销毁时,强制结束线程;

@Override
protected void onDestroy() {
   // 外部类Activity生命周期结束时,强制结束线程
   super.onDestroy();
   Thread.stop();
}

(3)Handler
将Handler声明为静态内部类,就不会持有外部类的引用,其生命周期就和外部类无关,
如果Handler里面需要context的话,可以通过弱引用方式引用外部类
Android 弱引用和软引用

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343

推荐阅读更多精彩内容

  • OOM(OutOfMemory)就是我们平时所碰到的内存溢出,而内存泄漏的最终后果就是导致OOM。内存泄漏是造成应...
    闲庭阅读 1,259评论 0 9
  • 先通俗理解下内存泄漏,内存溢出,OOM,GC回收这几个概念。 内存溢出(out of memory) : 是指程序...
    caoxiaoyun阅读 576评论 0 0
  • OOM简介 OOM全称为Out of memory,解释为内存溢出。 为了整个Android系统的内存控制需要,A...
    天平GG阅读 2,826评论 0 14
  • Android 内存泄漏总结 内存管理的目的就是让我们在开发中怎么有效的避免我们的应用出现内存泄漏的问题。内存泄漏...
    _痞子阅读 1,624评论 0 8
  • 什么是OOM 当前占用内存加上我们申请的内存资源超过了Dalvik虚拟机的最大内存限制就会抛出Out of mem...
    AKyS佐毅阅读 238评论 0 0