Android异常与性能优化问题

一、ANR(Application Not Responding)问题

1、什么是ANR(Application Not Responding)
ANR就是一个程序无响应的对话框

在一个Activity(Service)当中最长的执行时间是5秒,超出5秒无响应就会导致ANR
在一个BroadcastReceiver当中最长的执行时间是10秒,
原因:在主线程中做了耗时操作,所以才会导致ANR的弹框

2、造成ANR的主要原因

应用程序的响应性是由Activity Manager和WindowManager系统服务监视的,当它监测到Activity和BroadcastReceiver当中5秒、10秒没有执行完任务之后。安卓就会弹出ANR的对话框

  • 主线程被IO操作(从4.0之后网络IO不允许在主线程中)阻塞
  • 主线程中存在耗时操作
3、造成ANR的主要原因-Android中哪些操作是在主线程呢?
  • Activity的所有生命周期回调都是执行在主线程的
  • Service默认是执行在主线程的
  • BroadcastReceiver的onReceive回调是执行在主线程的
  • 没有使用子线程的looper的Handler的handlerMessage,post(Runnable)是执行在主线程的
  • AsyncTask的回调中除了doInBackground,其他都是执行在主线程
4、如何解决ANR
  • 使用AsyncTask处理耗时IO操作
  • 使用Thread或者HandlerThread提高优先级,不提高优先级 它的优先级和主线程的优先级是一样的仍然会造成ANR
  • 使用handler来处理工作线程的耗时任务
  • 在Activity的onCreate和onResume回调中尽量避免耗时的操作

二、OOM(Out of Memory)问题

1、什么是oom

当前占用的内存加上我们申请的内存资源超过了Dalvik虚拟机的最大内存限制就会抛出Out of memory异常,最常见的oom就是bitmap加载大图的时候。

2、一些容易混淆的概念
  • 内存溢出:就是Out of memory
  • 内存抖动:短时间内大量的对象被创建又被马上释放,瞬间产生的对象。会严重占用内存区域
  • 内存泄露:进程中的某些对象,比如说垃圾对象。已经没有被其他对象引用到了,但是它们确可以直接或间接引用到GCRoots。导致GC无法直接产生作用,一旦内存泄露累积到一定程度,就会引起内存溢出。
3、如何解决oom

1、有关bitmap优化

  • 图片的显示:比如ListView滑动的时候要显示缩略图不要去网络请求下载图片,只有监听到ListView停止滑动的时候再去加载网络大图
  • 及时释放内存
  • 图片压缩
  • inBitmap属性
  • 捕获异常

2、ListView

  • ConverView/Lru机制缓存bitmap
  • 避免在onDraw方法里面执行对象的创建,频繁的创建对象容易引起内存抖动
  • 谨慎使用多进程

三、Bitmap相关问题

bitmap是存在native内存和Java内存当中的,当被回收的时候分两部分回收。一是回收Java内存当中的内存二是回收native内存当中的内存。
1、Recycle

recycle释放bitmap内存的时候,会释放和这个bitmap有关的native内存,同时会清理有关数据对象的引用。但不是立即清理,它会给垃圾回收器发送消息指令。让它在没有其他对象引用这个bitmap对象的时候,进行垃圾回收。
当bitmap调用recycle之后,bitmap会被标记为“dead”。这个时候你再调用bitmap的其他方法就会引起异常。比如getPixels()或者setPixels(),同时recycle操作是不可逆的。所以你要确定被recycle之后不再调用这个bitmap对象以及它的任何方法,否则就会引起异常。官方建议我们不主动调用recycle方法,当没有对象引用这个bitmap的时候垃圾回收器会主动的回收这个对象。

2、LRU算法
  • lru算法是最近最少使用的对象,我们把它清除出缓存队列。
  • LruCache是一个泛型类,lru算法内部使用了一个LinkedHashMap来实现的,并且提供了get和put方法来完成缓存的添加和获取操作,当缓存满的时候它内部提供了一个trimToSize()的方法。把较早和最少使用的的缓存对象移除并添加新的缓存对象。
3、计算inSampleSize
// 根据maxWidth, maxHeight计算最合适的inSampleSize
    public static int calculateInSampleSize(
            BitmapFactory.Options options, int reqWidth, int reqHeight) {
        // 图像的原始高度和宽度
        final int height = options.outHeight;
        final int width = options.outWidth;
        int inSampleSize = 1;

        if (height > reqHeight || width > reqWidth) {
            if (width > height) {
                inSampleSize = Math.round((float)height / (float)reqHeight);
            } else {
                inSampleSize = Math.round((float)width / (float)reqWidth);
            }
        }
        return inSampleSize;
    }
4、缩略图
//缩略图
    public static Bitmap thumbnail(String path,
                                   int maxWidth, int maxHeight, boolean autoRotate) {
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        // 获取这个图片的宽和高信息到options中, 此时返回bm为空
        Bitmap bitmap = BitmapFactory.decodeFile(path, options);
        options.inJustDecodeBounds = false;
        // 计算缩放比
        int sampleSize = calculateInSampleSize(options, maxWidth, maxHeight);
        options.inSampleSize = sampleSize;
        options.inPreferredConfig = Bitmap.Config.RGB_565;
        options.inPurgeable = true;
        options.inInputShareable = true;
        if (bitmap != null && !bitmap.isRecycled()) {
            bitmap.recycle();
        }
        bitmap = BitmapFactory.decodeFile(path, options);
        return bitmap;
    }
5、三级缓存
  • 网络缓存
  • 本地缓存
  • 内存缓存

四、UI卡顿问题

1、UI卡顿原理

UI渲染系统做了太多的耗时操作,和执行了大量的动画。
60fps->16ms
过渡绘制:UI布局中有大量重叠的部分,多层次的UI结构中。

2.UI卡顿的原因分析
  • 人为在UI线程中做轻微耗时操作,导致UI线程卡顿
  • 布局Layout过于复杂,无法在16ms内完成渲染
  • 同一时间动画执行的次数过多,导致CPU或GPU负载过重
  • View过渡绘制,导致某些像素在同一帧时间内被绘制多次,从而使CPU或GPU负载过重
  • View频繁的触发measure、layout,导致measure、layout累计耗时过多及整个View频繁的重新渲染
  • 内存频繁触发GC过多,导致暂时阻塞渲染操作
  • 冗余资源及逻辑等导致加载和执行缓慢
  • ANR
3、UI卡顿总结
  • 布局优化:使用常见的include、merge、ViewStub标签。尽量不存在冗余嵌套或者复杂的布局
  • 列表及Adapter优化
  • 背景和图片等内存分配优化
  • 避免ANR

五、内存泄露问题

1、java内存的分配策略
  • 静态存储区(方法区)
    存放静态数据、全局变量。程序编译的时候已经分配好了,在静态存储区存储的变量,在程序运行的整个期间都会存在
  • 栈区
    方法内的局部变量,会在栈上创建存储空间。并在方法结束后,这些在变量所持有的内存会被自动释放
  • 堆区
    又称动态内存分配,通常就是我们new对象出来的内存。这部分内存在不使用的时候会有java的内存回收器进行回收
2、java中的内存泄露

内存泄露是指无用对象(不再使用的对象)持续占有内存或无用对象的内存得不到及时释放,从而造成的内存空间的浪费称为内存泄露。

六、Android内存管理机制

1、分配机制

操作系统会为每个进程分配一个合理大小的内存,从而保证每一个进程能够正常的运行。而不至于内存不够使用或者每个进程占用太多的内存

2、回收机制

在系统内存不够的时候,他会有一个合理的回收再分配机制从而保证新的进程能够正常的运行。

3、内存管理机制的特点
  • 更少的占用内存
  • 在合适的时候,合理的释放系统资源
  • 在系统内存紧张的情况下,能释放大部分不重要的资源,来为Android系统提供可用的内存
  • 能够很合理的在特殊生命周期,保存或者还原重要数据,以至于系统能够保证正确的重新恢复该应用
4、内存优化的方法
  • 当Service完成任务后,尽量停止它。推荐使用Intentservice
  • 在UI不可见的时候,释放掉一些只有UI使用的资源
  • 在系统内存紧张的时候,尽可能多的释放掉一些非重要资源
  • 避免滥用Bitmap导致的内存浪费
  • 使用针对内存优化过的数据容器:SparseArray
  • 避免使用依赖注入的框架
  • 使用ZIP对齐的APK
  • 使用多进程

七、冷启动优化

1、冷启动的定义

冷启动就是在启动应用前,系统中没有该应用的任何进程信息

2、冷启动和热启动的区别

热启动:用户使用返回键退出应用,然后马上又重新启动应用。热启动的应用的进程是保留在后台的

  • 冷启动:每次启动的时候都会走Application这个类,
  • 热启动:进程中保留留这个app的进行,它会直接走MainActivity这个类
3、冷启动的流程
  • Zygote进程中fork创建出一个新的进程
  • 创建和初始化Application类、创建MainActivity类inflate布局
  • 当onCreate/onStart/onResume方法都走完
  • contentView的measure/layout/draw显示在界面上
4、冷启动流程-总结

Application的构造方法->attachBaseContext()->onCreate()->Activity的构造方法->onCreate()->配置主题中背景等属性->onStart()->onResume()->测量布局绘制显示在界面上

5、 如何对冷启动的时间进行优化
  • 减少onCreate()方法的工作量
  • 不要让Application参与业务的操作
  • 不要在Application进行耗时操作
  • 不要以静态变量的方式在Application中保存数据
  • 布局(减少布局的复杂性)、mainThread(资源的初始化放到子线程当中)

八、其他优化问题

1、Android不用静态变量储存数据
  • 静态变量等数据由于进程已经被杀死而被从新初始化
  • 使用其他数据传输方式:文件、SP、contentProvider,要对数据进行非空判断
2、有关SharePreference问题
  • 不能跨进程同步
  • 存储SharePreference的文件过大问题,文件过大获取值得时候,有可能阻塞主线程。解析很大的SharePreference文件的时候会产生大量的临时文件对象,导致垃圾回收机制频繁的进行垃圾回收。容易造成UI卡顿和内存抖动
3、内存对象的序列化

序列化:将对象的状态信息转换为可以储存或传输的形式的过程

  • Serializeble:Serializeble在序列化的时候会产生大量的临时变量,从而引起频繁的垃圾回收。影响UI卡顿,容易引起内存抖动,造成oom
  • Parcelable:不能使用存储在磁盘上的文件
4、 内存对象序列化-总结
  • Serializeble是java的序列化方式,Parcelable是Android特有的序列化方式
  • 在使用内存的时候,Parcelable比Serializeble性能高
  • Serializeble在序列化的时候会产生大量的临时变量,从而引起频繁的GC
  • Parcelable不能使用在要将数据存储在磁盘上的情况

推荐使用Serializeble进行数据序列化

避免在UI线程中做繁重的操作

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

推荐阅读更多精彩内容