栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Android中性能优化相关知识点

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Android中性能优化相关知识点

目录

1.ANR定义

2.产生ANR的时间限制

3.ANR产生的原因

4.ANR产生的原因详细分析

5.Android中哪些操作是在主线程

6.如何解决ANR

7.OOM定义

8.OOM出现的原理

9.OOM出现的主要场景

10.内存溢出、内存抖动、内存泄漏的区别

11.如何解决OOM

12.Bitmap.recycle()方法说明

13.LruCache源码分析


1.ANR定义

在Android当中,如果我们的应用程序有一段时间点击不够灵敏,系统就会向用户显示一个对话框。而这个对话框的内容就是ANR,也就是Application Not Responding。这个对话框让用户可以选择等待,程序可以继续运行;同时也可以让用户选择关闭。所以说对于一个流畅的、用户体验良好的、合理的APP当中,是绝对不能出现ANR的。如果出现ANR,势必要让用户处理这个对话框。而这个对话框是十分影响体验的。

2.产生ANR的时间限制

在默认情况下,在一个Activity当中,最长的执行时间是5秒。如果超过了5秒没有做出响应,那就会出现这个ANR的弹框。而在BroadcastReceiver广播接收者当中,最长的执行时间是10秒。你可以在10秒钟之内作出一些操作。如果超出10秒还没有完成,就会造成ANR。

3.ANR产生的原因

在主线程中做了耗时操作,所以才会导致ANR的弹框。

4.ANR产生的原因详细分析

应用程序的响应性是由Activity Manager和WindowManager系统服务监视的。当它监视到Activity或BroadcastReceiver当中在规定时间没有执行完任务时,Android就会弹出ANR的对话框。

而造成ANR的主要原因有两点:

<1>主线程被IO操作(从4.0之后网络IO不允许在主线程中)阻塞。

<2>主线程中存在耗时的计算。

这两个原因归结到的根本都是在主线程中做了非常耗时的操作,就像下载、IO流的读取等等。所以说要尽量把耗时的网络、数据库读取操作,高耗时的一些计算等都放在子线程中完成。之后可以通过Android中的Handler机制,在子线程的任务完成之后,通过Handler将消息转发到主线程中,在主线程进行相关的UI绘制工作。

5.Android中哪些操作是在主线程

<1>Activity的所有生命周期回调都是执行在主线程的。

<2>Service默认是执行在主线程的(如果Service想做耗时操作可以使用IntentService)。

<3>BroadcastReceiver的onReceive回调是执行在主线程的。

<4>没有使用子线程Looper的Handler的handleMessage,post(Runnable)是执行在主线程的。

<5>AsyncTask的回调中除了doInBackground,其他都是执行在主线程。

6.如何解决ANR

<1>使用AsyncTask处理耗时IO操作。AsyncTask是一个灵活的切换子线程到UI线程的机制。

<2>使用Thread或者HandlerThread提高优先级。我们知道,Thread和HandlerThread它都能开启个子线程,区别是后者HandlerThread它在子线程中可以创建Handler来发送消息。因为它内部创建了Looper并关联了消息队列,所以说它能创建Handler。而Thread中是不能创建Handler的。

<3>使用Handler来处理工作线程的耗时任务。

<4>Activity的onCreate和onResume回调中尽量避免耗时的代码。

7.OOM定义

当前占用的内存加上我们申请的内存资源超过了Dalvik虚拟机的最大内存限制就会抛出Out of Memory异常。

8.OOM出现的原理

在Android中,Android系统会为每一个APP分配一个独立的内存空间,即Dalvik虚拟机空间。这样每个APP都可以运行在独立的空间上,而不受其它APP影响。但是我们要知道,Android系统为每一个Dalvik虚拟机都设定了一个最大的内存限制。如果当前占用的内存,加上我们申请的内存资源超过了这个限制,系统就会抛出OOM异常。

9.OOM出现的主要场景

OOM异常在项目开发过程中经常遇到的就是有关于Bitmap大图加载的时候出现。所以说大部分的OOM问题都和Bitmap加载有关。

10.内存溢出、内存抖动、内存泄漏的区别

<1>内存溢出:即Out of Memory,就是当前占用的内存,加上所要申请的内存资源,超过了虚拟机所能承受的最大内存限制时,它就会抛出内存溢出,即Out of Memory这个异常。

<2>内存抖动:短时间内大量的对象被创建,然后又被马上释放,瞬间产生的对象会严重占用内存区。当达到阈值时,它就会触发GC,即垃圾回收。这样你刚刚产生的对象很快又被回收。也就说每一次分配对象占用很少的内存,但是它们叠加在一起就会造成堆内存的压力,从而触发更多的GC,即产生内存抖动。

<3>内存泄漏

进程中的某些对象,比如垃圾对象,它已经没有被其它地方引用到了,但是它们却可以直接或间接引用到其它还没有被回收的对象,导致GC无法产生作用。所以说一旦内存泄漏累积到一定程度,它会造成内存溢出,也就是OOM。

11.如何解决OOM

<1>Bitmap相关方面

  • 图片显示:我们要加载合适的图片。要显示缩略图时,我们不要请求网络加载大图,这也是一种优化机制。比如在listview中,我们会监听滑动事件,在滑动的时候不去调用网络请求。只有监听到listview它滑动停止时,我们再去加载大图,图片显示到ImageView上。
  • 及时释放内存:首先我们知道,Android系统它其实有自己的垃圾回收机制,也就是java的垃圾回收机制。它可以不定期回收掉不使用的内存空间。同时我们还知道,Bitmap它的构造方法都是私有的,它是通过BitmapFactory这个类来实例化一个Bitmap。BitmapFactory所有生成Bitmap对象都是通过JNI调用方式实现的。所以Bitmap加载到内存后,它是包含两部分内存区域的。简单说就是一部分为java区,一部分为C区。而这个Bitmap对象它是由java部分分配的,不用的时候它会由java的GC回收机制回收掉。而对应的C的那份内存区域,虚拟机是不能直接回收的,所以只能调用底层功能释放。因此,这里说的释放内存释放的其实是C那部分的内存。释放的方法就是调用Bitmap.recycle(),这个方法里面会使用JNI调用对应的底层C语言方法。但事实上不调用该方法也不会OOM。
  • 图片压缩:如果一开始就要加载一个很大很大的大图,这个大图它直接超过了内存分配大小,这样就肯定会导致内存溢出。所以这时候就要对加载Bitmap大小进行控制,也就是进行图片压缩。而对Bitmap进行压缩,需要用到Bitmap一个InSampleSize缩放比例的属性。就是把图片加载到内存之前,我们需要计算一个合适的缩放比,避免不必要的大图载入。
  • inBitmap属性:它可以提高Android系统在Bitmap分配和释放的执行效率。这个inBitmap属性可以告知Bitmap的decode解码器,在使用已经存在的内存区域,而不是重新申请一块内存区域放Bitmap。即调用decodeBitmap获取新的Bitmap时,它会使用之前那张Bitmap在堆内存中占用的那块内存区域。也就是说,你即使有成百上千张图片,它也只占用屏幕可放下的那么多图片的内存。
  • 捕获异常:Android系统在读取bitmap时,它分给虚拟机中图片的堆栈大小是有限制的。因此为了避免应用在分配bitmap内存时出现OOM,在实例化bitmap时,一定要对Out of Memory进行异常的捕获。注意,如果捕获Exception是捕获不到的,因为OOM是一个Error。

<2>其他方面

  • listview相关:一个是使用convertView的复用,另一个是对ListView当中大图控件要用lru机制缓存Bitmap。lru是最近最少使用的图片机制,它是个三级缓存机制。
  • 避免在onDraw方法里面执行对象的创建:如果在onDraw方法中频繁调用创建对象操作,手机内存会突然上升,然后释放内存时就会造成频繁的GC,这样就会造成前面所说的内存抖动现象。内存抖动积累到一定程度也会OOM,所以这里也是需要避免的。
  • 谨慎使用多进程:多进程就是可以把应用中的部分组件运行在单独的进程当中。比如定位,比如webview也可以单独开启一个进程避免内存泄漏。开启单独进程可以扩大内存占用范围。但一定要谨慎使用。多进程代码更加复杂,逻辑更加繁琐,如果使用不当,不仅会造成内存增长,也会造成其他莫名其妙的crash。

12.Bitmap.recycle()方法说明

recycle表示它在释放bitmap内存的时候,它会释放和这个bitmap有关的native内存,同时它会清理有关数据对象的引用。但是这里处理数据对象的引用不是立即清理数据。就是说它不是你调用完这个recycle方法,它就会直接清理native内存。它只是给垃圾回收器发出一条指令,让它在没有其它对象引用这个bitmap对象的时候,会进行垃圾回收。当调用recycle方法之后,这个Bitmap就会被标明为"dead"状态,这时再调用bitmap相关的其它方法,就会引起异常。同时recycle操作是不可逆的,所以说你一定务必要确认好这个Bitmap在以后的场景下不会被你的程序使用到,然后再去谨慎调用recycle方法。因为你调用recycle方法,这个Bitmap就被标为死亡状态,你不能调用它任何的回调方法。官方建议我们不用主动调用recycle方法,因为垃圾回收器,当没有其它对象引用指向该bitmap的时候,它会主动清理内存。我们要根据具体场景决定该方法的调用。

13.LruCache源码分析

<1>LRU算法的意思是最近最少使用的对象,把它清除出队列。LRU算法它其实是一个泛型类LruCache。它内部是用linkedHashMap实现的。它里面提供了get、put方法来完成缓存的添加和获取操作。当缓存满的时候,LRU算法会提供一个trimToSize方法,把较早的缓存对象移除,然后添加新的缓存对象。

<2>trimToSize方法解析

    public void trimToSize(int maxSize) {
        while (true) {
            K key;
            V value;
            synchronized (this) {
                if (size < 0 || (map.isEmpty() && size != 0)) {
                    throw new IllegalStateException(getClass().getName()
                            + ".sizeOf() is reporting inconsistent results!");
                }

                if (size <= maxSize) {
                    break;
                }

                Map.Entry toEvict = map.eldest();
                if (toEvict == null) {
                    break;
                }

                key = toEvict.getKey();
                value = toEvict.getValue();
                map.remove(key);
                size -= safeSizeOf(key, value);
                evictionCount++;
            }

            entryRemoved(true, key, value, null);
        }
    }

这个方法就是说,当它缓存满的时候,这个算法就会移除较早的缓存对象,然后把新的缓存对象添加到这个队列当中。trimToSize方法中做了一个同步代码块的判断

synchronized (this) {

    ...

}

在同步代码块中有如下语句

synchronized (this) {

    if (size < 0 || (map.isEmpty() && size != 0)) {
        throw new IllegalStateException(getClass().getName() + ".sizeOf() is reporting inconsistent results!");
    }

    if (size <= maxSize) {
        break;
    }


    ...

}

这里有两个if判断,就是说当里面元素的尺寸小于了它的最大值,我们就会退出循环。

接下来代码其实是做个判断,它计算剩余的size到底有多少。然后我们可以通过它不断地循环在这个if里边做判断。如果小于它的最大值就终止循环。移除时用的是HashMap的remove方法。remove内部调用了removeEntryForKey,它也是使用key值删除对应的值。接着通过safeSizeOf方法计算当前缓存队列的大小,然后从总大小中把它减掉。

(未完待续)

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/678022.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号