Android性能优化之网络优化(史上最全总结)一文了解清清楚楚:网络优化方法

媒介

app开发中,图片是少不了的收集优化办法。各类图标图片资本,若是不克不及很好的处置图片的操纵。会招致app性能严峻下降,影响用户体验,最曲不雅的感触感染就是卡顿,手机发热,有时候还OOM,

那么今天我们就来阐发oom和内存优化总结;

Android性能优化之收集优化(史上最全总结)一文领会清清晰楚

一、什么是OOM收集优化办法?

OOM收集优化办法,全称“Out Of Memory”,翻译成中文就是“内存用完了”,来源于java.lang.OutOfMemoryError;当JVM因为没有足够的内存来为对象分配空间而且垃圾收受接管器也已经没有空间可收受接管时,就会抛出那个error(注:非exception,因为那个问题已经严峻到不敷以被应用途理);在客户端App中那个现象凡是呈现在用到良多图片或者很大图片的APP开发中;通俗讲就是当我们的APP需要申请一块内存来拆图片的时候,系统觉得我们的APP所利用的内存已经够多了,即便它有1G的空余内存,它差别意给我的APP更多的内存里,然后即便系统马上抛出OOM错误,而法式没有捕获该错误,故弹框瓦解了;二、OOM的类型

1、JVM内存模子:

根据JVM标准收集优化办法,JAVA虚拟机在运行时会办理以下的内存区域:

法式计数器:当前线程施行的字节码的行号指示器,线程私有;JAVA虚拟机栈:Java办法施行的内存模子,每个Java办法的施行对应着一个栈帧的进栈和出栈的操做;当地办法栈:类似“ JAVA虚拟机栈 ”,但是为native办法的运行供给内存情况;JAVA堆:对象内存分配的处所,内存垃圾收受接管的次要区域,所有线程共享收集优化办法。可分为重生代,老生代;办法区:用于存储已经被JVM加载的类信息、常量、静态变量、立即编译器编译后的代码等数据。Hotspot中的“永久代”;运行时常量池:办法区的一部门,存储常量信息,如各类字面量、符号引用等;间接内存:并非JVM运行时数据区的一部门, 可间接拜候的内存, 好比NIO会用到那部门;根据JVM标准,除了法式计数器不会抛出OOM外,其他各个内存区域都可能会抛出OOM;2、最常见的OOM情况有以下三种:

java.lang.OutOfMemoryError: Java heap space ------>java堆内存溢出,此种情况最常见,一般因为内存泄露或者堆的大小设置不妥引起收集优化办法。关于内存泄露,需要通过内存监控软件查找法式中的泄露代码,而堆大小能够通过虚拟机参数-Xms,-Xmx等修改;java.lang.OutOfMemoryError: PermGen space ------>java永久代溢出,即办法区溢出了,一般呈现于大量Class或者jsp页面,或者接纳cglib等反射机造的情况,因为上述情况会产生大量的Class信息存储于办法区。此种情况能够通过更改办法区的大小来处理,利用类似-XX:PermSize=64m -XX:MaxPermSize=256m的形式修改。别的,过多的常量尤其是字符串也会招致办法区溢出;java.lang.StackOverflowError ------> 不会抛OOM error,但也是比力常见的Java内存溢出。JAVA虚拟机栈溢出,一般是因为法式中存在死轮回或者深度递归挪用形成的,栈大小设置太小也会呈现此种溢出。能够通过虚拟机参数-Xss来设置栈的大小;三、为什么会OOM?

android系统的app的每个历程或者每个虚拟机有个更大内存限造收集优化办法,若是申请的内存资本超越那个限造,系统就会抛出OOM错误;

跟整个设备的剩余内存没太大关系收集优化办法。好比比力早的android系统的一个虚拟机最多16M内存,当一个app启动后,虚拟机不断的申请内存资本来拆载图片,当超越内存上限时就呈现OOM

seo0335.net/zb_users/upload/2021-08-29/0e6c468e6782834b2702c6b84811487a.jpg" alt="Android性能优化之收集优化(史上最全总结)一文领会清清晰楚">

为什么会没有内存了呢收集优化办法?原因不过乎有两点:

1、分配的少了:好比虚拟机自己可利用的内存(一般通过启动时的VM参数指定)太少;

2、应用用的太多收集优化办法,而且用完没释放,浪费了,此时就会形成内存泄露或者内存溢出;

内存泄露:申请利用完的内存没有释放,招致虚拟机不克不及再次利用该内存,此时那段内存就泄露了,因为申请者不消了,而又不克不及被虚拟机分配给他人用;内存溢出:申请的内存超出了JVM能供给的内存大小,此时称之为溢出;在之前没有垃圾主动收受接管的日子里,好比C语言和C++语言,我们必需亲身负责内存的申请与释放操做,若是申请了内存,用完后又忘记了释放,好比C++中的new了但是没有delete,那么就可能形成内存泄露收集优化办法。偶然的内存泄露可能不会形成问题,而大量的内存泄露可能会招致内存溢出;

而在Java语言中,因为存在了垃圾主动收受接管机造,所以,我们一般不消去主动释放不消的对象所占的内存,也就是理论上来说,是不会存在“内存泄露”的收集优化办法。但是,若是编码不妥,好比,将某个对象的引用放到了全局的Map中,固然办法完毕了,但是因为垃圾收受接管器会按照对象的引用情况来收受接管内存,招致该对象不克不及被及时的收受接管。若是该种情况呈现次数多了,就会招致内存溢出,好比系统中经常利用的缓存机造。Java中的内存泄露,差别于C++中的忘了delete,往往是逻辑上的原因泄露。

四、若何躲避OOM和停止内存优化

1、减小对象的内存占用

制止OOM的第一步就是要尽量削减新分配出来的对象占用内存的大小,尽量利用愈加轻量的对象收集优化办法。

1)利用愈加轻量的数据构造

我们能够考虑利用ArrayMap/SparseArray而不是HashMap等传统数据构造收集优化办法。

HashMap的简要工做原理,比拟起Android专门为挪动操做系统编写的ArrayMap容器,在大大都情况下,都显示效率低下,更占内存收集优化办法。

凡是的HashMap的实现体例愈加消耗内存,因为它需要一个额外的实例对象来记录Mapping操做收集优化办法。

别的,SparseArray愈加高效,在于他们制止了对key与value的主动拆箱(autoboxing),而且制止了拆箱后的解箱收集优化办法。

2)制止在Android里面利用Enum

列举凡是需要两倍于静态常量的内存收集优化办法。您应该严酷制止在Android上利用列举。,所以请制止在Android里面利用到列举。

3)减小Bitmap对象的内存占用

Bitmap是一个极容易消耗内存的大胖子收集优化办法,减小创建出来的Bitmap的内存占用可谓是重中之重,凡是来说有以下2个办法

inSampleSize:缩放比例,在把图片载入内存之前,我们需要先计算出一个适宜的缩放比例,制止没必要要的大图载入收集优化办法。

decode format:解码格局,选择ARGB_8888/RBG_565/ARGB_4444/ALPHA_8,存在很大差别收集优化办法。

4)利用更小的图片

在涉及给到资本图片时,我们需要出格留意那张图片能否存在能够压缩的空间,能否能够利用更小的图片收集优化办法。尽量利用更小的图片不只能够削减内存的利用,还能制止呈现大量的InflationException。假设有一张很大的图片被XML文件间接引用,很有可能在初始化视图时会因为内存不敷而发作InflationException,那个问题的底子原因其实是发作了OOM。

2、内存对象的反复操纵

大大都对象的复用,最末施行的计划都是操纵对象池手艺,要么是在编写代码时显式地在法式里创建对象池,然后处置好复用的实现逻辑收集优化办法。要么就是操纵系统框架既有的某些复用特征,削减对象的反复创建,从而降低内存的分配与收受接管;复用系统自带的资本:Android系统自己内置了良多的资本,例如字符串/颜色/图片/动画/款式以及简单规划等等,那些资本都能够在应用法式中间接引用。如许做不单单能够削减应用法式的本身负重,减小APK的大小,别的还能够必然水平上削减内存的开销,复用性更好。但是也有需要留意Android系统的版本差别性,对那些差别系统版本上表示存在很大差别,不契合需求的情况,仍是需要应用法式本身内置进去;留意在ListView/GridView等呈现大量反复子组件的视图里面临ConvertView的复用;Bitmap对象的复用;制止在onDraw办法里面施行对象的创建;类似onDraw等频繁挪用的办法,必然需要留意制止在那里做创建对象的操做,因为他会敏捷增加内存的利用,并且很容易引起频繁的gc,以至是内存颤动;StringBuilder:在有些时候,代码中会需要利用到大量的字符串拼接的操做,那种时候有需要考虑利用StringBuilder来替代频繁的“+”;3、制止对象的内存泄露

内存对象的泄露,会招致一些不再利用的对象无法及时释放,如许一方面占用了贵重的内存空间,很容易招致后续需要分配内存的时候,空闲空间不敷而呈现OOM收集优化办法。显然,那还使得每级Generation的内存区域可用空间变小,GC就会更容易被触发,容易呈现内存颤动,从而引起性能问题

1)留意Activity的泄露

凡是来说,Activity的泄露是内存泄露里面最严峻的问题,它占用的内存多,影响面广,我们需要出格留意以下两种情况招致的Activity泄露:内部类引用招致Activity的泄露:最典型的场景是Handler招致的Activity泄露,若是Handler中有延迟的使命或者是期待施行的使命队列过长,都有可能因为Handler继续施行而招致Activity发作泄露收集优化办法。此时的引用关系链是Looper -> MessageQueue -> Message -> Handler -> Activity。为领会决那个问题,能够在UI退出之前,施行remove Handler动静队列中的动静与runnable对象。或者是利用Static + WeakReference的体例来到达断开Handler与Activity之间存在引用关系的目标。Activity Context被传递到其他实例中,那可能招致本身被引用而发作泄露;内部类引起的泄露不单单会发作在Activity上,其他任何内部类呈现的处所,都需要出格留意!我们能够考虑尽量利用static类型的内部类,同时利用WeakReference的机造来制止因为互相引用而呈现的泄露;2)考虑利用Application Context而不是Activity Context

关于大部门非必需利用Activity Context的情况(Dialog的Context就必需是Activity Context)收集优化办法,我们都能够考虑利用Application Context而不是Activity的Context,如许能够制止不经意的Activity泄露;

3)留意临时Bitmap对象的及时收受接管

固然在大大都情况下,我们会对Bitmap增加缓存机造,但是在某些时候,部门Bitmap是需要及时收受接管的收集优化办法。例如临时创建的某个相比照较大的bitmap对象,在颠末变更得到新的bitmap对象之后,应该尽快收受接管原始的bitmap,如许可以更快释放原始bitmap所占用的空间。需要出格留意的是Bitmap类里面供给的createBitmap()办法:那个函数返回的bitmap有可能和source bitmap是统一个,在收受接管的时候,需要出格查抄source bitmap与return bitmap的引用能否不异,只要在不等的情况下,才气够施行source bitmap的recycle办法。4)留意监听器的登记

在Android法式里面存在良多需要register与unregister的监听器,我们需要确保在适宜的时候及时unregister那些监听器收集优化办法。本身手动add的listener,需要记得及时remove那个listener。

5)留意缓存容器中的对象泄露

有时候,我们为了进步对象的复用性把某些对象放到缓存容器中,可是若是那些对象没有及时沉着器中肃清,也是有可能招致内存泄露的收集优化办法。例如,针对2.3的系统,若是把drawable添加到缓存容器,因为drawable与View的强应用,很容易招致activity发作泄露。而从4.0起头,就不存在那个问题。处理那个问题,需要对2.3系统上的缓存drawable做特殊封拆,处置引用解绑的问题,制止泄露的情况。

6)留意WebView的泄露

Android中的WebView存在很大的兼容性问题,不单单是Android系统版本的差别对WebView产生很大的差别,别的差别的厂商出货的ROM里面WebView也存在着很大的差别收集优化办法。更严峻的是尺度的WebView存在内存泄露的问题,请看 那里。所以凡是根治那个问题的法子是为WebView开启别的一个历程,通过AIDL与主历程停止通信,WebView所在的历程能够按照营业的需要选择适宜的时机停止销毁,从而到达内存的完好释放。

7)留意Cursor对象能否及时封闭

在法式中我们经常会停止查询数据库的操做,但时常会存在不小心利用Cursor之后没有及时封闭的情况收集优化办法。那些Cursor的泄露,频频屡次呈现的话会对内存办理产生很大的负面影响,我们需要谨记对Cursor对象的及时封闭。

4、内存利用战略优化

1)隆重利用large heap

正如前面提到的,Android设备按照硬件与软件的设置差别而存在差别大小的内存空间,他们为应用法式设置了差别大小的Heap限造阈值收集优化办法。你能够通过挪用getMemoryClass()来获取应用的可用Heap大小。在一些特殊的情景下,你能够通过在manifest的application标签下添加largeHeap=true的属性来为应用声明一个更大的heap空间。然后,你能够通过getLargeMemoryClass()来获取到那个更大的heap size阈值。然而,声明得到更大Heap阈值的本意是为了一小部门会消耗大量RAM的应用(例如一个大图片的编纂应用)。不要随便的因为你需要利用更多的内存而去恳求一个大的Heap Size。只要当你清晰的晓得哪里会利用大量的内存而且晓得为什么那些内存必需被保留时才去利用large heap。因而请隆重利用large heap属性。利用额外的内存空间会影响系统整体的用户体验,而且会使得每次gc的运行时间更长。在使命切换时,系统的性能会大打折扣。别的, large heap其实不必然可以获取到更大的heap。在某些有严酷限造的机器上,large heap的大小和凡是的heap size是一样的。因而即便你申请了large heap,你仍是应该通过施行getMemoryClass()来查抄现实获取到的heap大小。2)综合考虑设备内存阈值与其他因素设想适宜的缓存大小

在设想ListView或者GridView的Bitmap LRU缓存的时候收集优化办法,需要考虑的点有:

应用法式剩下了几可用的内存空间?有几图片会被一次呈现到屏幕上?有几图片需要事先缓存好以便快速滑动时可以立即显示到屏幕?设备的屏幕大小与密度是几? 一个xhdpi的设备会比hdpi需要一个更大的Cache来hold住同样数量的图片收集优化办法。差别的页面针对Bitmap的设想的尺寸与设置装备摆设是什么,大要会破费几内存?页面图片被拜候的频次?能否存在此中的一部门比其他的图片具有更高的拜候频繁?若是是,也许你想要保留那些最常拜候的到内存中,或者为差别组此外位图(按拜候频次分组)设置多个LruCache容器。3)onLowMemory()与onTrimMemory()

Android用户能够随意在差别的应用之间停止快速切换收集优化办法。为了让background的应用可以敏捷的切换到forground,每一个background的应用城市占用必然的内存。Android系统会按照当前的系统的内存利用情况,决定收受接管部门background的应用内存。若是background的应用从暂停形态间接被恢复到forground,可以获得较快的恢复体验,若是background应用是从Kill的形态停止恢复,比拟之下就显得略微有点慢。

onLowMemory():Android系统供给了一些回调来通知当前应用的内存利用情况,凡是来说,当所有的background应用都被kill掉的时候,forground应用会收到onLowMemory()的回调收集优化办法。在那种情况下,需要尽快释放当前应用的非必需的内存资本,从而确保系统可以继续不变运行。onTrimMemory(int):Android系统从4.0起头还供给了onTrimMemory()的回调,当系统内存到达某些前提的时候,所有正在运行的应用城市收到那个回调,同时在那个回调里面会传递以下的参数,代表差别的内存利用情况,收到onTrimMemory()回调的时候,需要按照传递的参数类型停止判断,合理的选择释放本身的一些内存占用,一方面能够进步系统的整体运行流利度,别的也能够制止本身被系统判断为优先需要杀掉的应用。TRIM_MEMORY_UI_HIDDEN:你的应用法式的所有UI界面被隐藏了,即用户点击了Home键或者Back键退出应用,招致应用的UI界面完全不成见。那个时候应该释放一些不成见的时候非必需的资本当法式正在前台运行的时候,可能会领受到从onTrimMemory()中返回的下面的值之一:

TRIM_MEMORY_RUNNING_MODERATE:你的应用正在运行而且不会被列为可杀死的收集优化办法。但是设备此时正运行于低内存形态下,系统起头触发杀死LRU Cache中的Process的机造。TRIM_MEMORY_RUNNING_LOW:你的应用正在运行且没有被列为可杀死的。但是设备正运行于更低内存的形态下,你应该释放不消的资本用来提拔系统性能。TRIM_MEMORY_RUNNING_CRITICAL:你的应用仍在运行,但是系统已经把LRU Cache中的大大都历程都已经杀死,因而你应该立即释放所有非必需的资本。若是系统不克不及收受接管到足够的RAM数量,系统将会肃清所有的LRU缓存中的历程,而且起头杀死那些之前被认为不该该杀死的历程,例如阿谁包罗了一个运行态Service的历程。当应用历程退到后台正在被Cached的时候,可能会领受到从onTrimMemory()中返回的下面的值之一:

TRIM_MEMORY_BACKGROUND: 系统正运行于低内存形态而且你的历程正处于LRU缓存名单中最不容易杀掉的位置收集优化办法。虽然你的应用历程并非处于被杀掉的高危险形态,系统可能已经起头杀掉LRU缓存中的其他历程了。你应该释放那些容易恢复的资本,以便于你的历程能够保留下来,如许当用户回退到你的应用的时候才气够敏捷恢复。TRIM_MEMORY_MODERATE: 系统正运行于低内存形态而且你的历程已经已经接近LRU名单的中部位置。若是系统起头变得愈加内存严重,你的历程是有可能被杀死的。TRIM_MEMORY_COMPLETE: 系统正运行于低内存的形态而且你的历程正处于LRU名单中最容易被杀掉的位置。你应该释听任何不影响你的应用恢复形态的资本。因为onTrimMemory()的回调是在API 14才被加进来的,关于老的版本,你能够利用onLowMemory)回调来停止兼容。onLowMemory相当与TRIM_MEMORY_COMPLETE。

请留意:当系统起头肃清LRU缓存中的历程时,固然它起首根据LRU的挨次来施行操做,但是它同样会考虑历程的内存利用量以及其他因素收集优化办法。占用越少的历程越容易被留下来。

4)资本文件需要选择适宜的文件夹停止存放

我们晓得hdpi/xhdpi/xxhdpi等等差别dpi的文件夹下的图片在差别的设备上会颠末scale的处置收集优化办法。例如我们只在hdpi的目次下放置了一张100100的图片,那么按照换算关系,xxhdpi的手机去引用那张图片就会被拉伸到200200。需要留意到在那种情况下,内存占用是会显著进步的。关于不希望被拉伸的图片,需要放到assets或者nodpi的目次下。

5)Try catch某些大内存分配的操做

在某些情况下,我们需要事先评估那些可能发作OOM的代码,关于那些可能发作OOM的代码,参加catch机造,能够考虑在catch里面测验考试一次降级的内存分配操做收集优化办法。例如decode bitmap的时候,catch到OOM,能够测验考试把采样比例再增加一倍之后,再次测验考试decode。

6)隆重利用static对象

因为static的生命周期过长,和应用的历程连结一致,利用不妥很可能招致对象泄露,在Android中应该隆重利用static对象收集优化办法。

7)出格留意单例对象中不合理的持有

固然单例形式简单适用,供给了良多便当性,但是因为单例的生命周期和应用连结一致,利用不合理很容易呈现持有对象的泄露收集优化办法。

8)爱护保重Services资本

若是你的应用需要在后台利用service,除非它被触发并施行一个使命,不然其他时候Service都应该是停行形态收集优化办法。别的需要留意当那个service完成使命之后因为停行service失败而引起的内存泄露。 当你启动一个Service,系统会倾向为了保留那个Service而不断保留Service所在的历程。那使得历程的运行代价很高,因为系统没有法子把Service所占用的RAM空间腾出来让给其他组件,别的Service还不克不及被Paged out。那削减了系统可以存放到LRU缓存傍边的历程数量,它会影响应用之间的切换效率,以至会招致系统内存利用不不变,从而无法继续连结住所有目前正在运行的service。 建议利用IntentService,它会在处置完交代给它的使命之后尽快完毕本身。更多信息,请阅读 Running in a Background Service。

9)优化规划条理收集优化办法,削减内存消耗

越扁平化的视图规划,占用的内存就越少,效率越高收集优化办法。我们需要尽量包管规划足够扁平化,当利用系统供给的View无法实现足够扁平的时候考虑利用自定义View来到达目标。

10)隆重利用“笼统”编程

良多时候,开发者会利用笼统类做为”好的编程理论”,因为笼统可以提拔代码的灵敏性与可维护性收集优化办法。然而,笼统会招致一个显著的额外内存开销:他们需要同等量的代码用于可施行,那些代码会被mapping到内存中,因而若是你的笼统没有显著的提拔效率,应该尽量制止他们。

11)利用nano protobufs序列化数据

Protocol buffers是由Google为序列化构造数据而设想的,一种语言无关,平台无关,具有优良的扩展性收集优化办法。类似XML,却比XML愈加轻量,快速,简单。若是你需要为你的数据实现序列化与协议化,建议利用nano protobufs。关于更多细节,请参考 protobuf readme的”Nano version”章节。

12)隆重利用依赖注入框架

那些注入框架会通过扫描你的代码施行许多初始化的操做,那会招致你的代码需要大量的内存空间来mapping代码,并且mapped pages会长时间的被保留在内存中收集优化办法。除非实的很有需要,建议隆重利用那种手艺;

13)隆重利用多历程

利用多历程能够把应用中的部门组件运行在零丁的历程傍边,如许能够扩大应用的内存占用范畴,但是那个手艺必需隆重利用,绝大大都应用都不该该贸然利用多历程,一方面是因为利用多历程会使得代码逻辑愈加复杂,别的若是利用不妥,它可能反而会招致显著增加内存收集优化办法。当你的应用需要运行一个常驻后台的使命,并且那个使命其实不轻量,能够考虑利用那个手艺;一个典型的例子是创建一个能够长时间后台播放的Music Player。若是整个应用都运行在一个历程中,当后台播放的时候,前台的那些UI资本也没有法子得到释放。类似如许的应用能够切分红2个历程:一个用来操做UI,别的一个给后台的Service。14)利用ProGuard来剔除不需要的代码

ProGuard可以通过移除不需要的代码,重定名类,域与办法等等对代码停止压缩,优化与混淆收集优化办法。利用ProGuard能够使得你的代码愈加紧凑,如许可以削减mapping代码所需要的内存空间。

15)隆重利用第三方libraries

良多开源的library代码都不是为挪动收集情况而编写的,若是运用在挪动设备上,其实不必然合适收集优化办法。即便是针对Android而设想的library,也需要出格隆重,出格是在你不晓得引入的library详细做了什么工作的时候。例如,此中一个library利用的是nano protobufs, 而别的一个利用的是micro protobufs。如许一来,在你的应用里面就有2种protobuf的实现体例。如许类似的抵触还可能发作在输出日记,加载图片,缓存等等模块里面。别的不要为了1个或者2个功用而导入整个library,若是没有一个适宜的库与你的需求相吻合,你应该考虑本身去实现,而不是导入一个大而全的处理计划。

总结

内存优化其实不就是说法式占用的内存越少就越好,若是因为想要连结更低的内存占用,而频繁触发施行gc操做,在某种水平上反而会招致应用性能整体有所下降,那里需要综合考虑做必然的权衡收集优化办法。Android的内存优化涉及的常识面还有良多:内存办理的细节,垃圾收受接管的工做原理,若何查找内存泄露等等都能够展开讲良多。OOM是内存优化傍边比力凸起的一点,尽量削减OOM的概率对内存优化有着很大的意义

打造最大的挖矿交流社区
SEO交流,纯交流无广告,SEO网站优化机器,小白变大神,期待你的加入!

标签: 网络优化方法

作者头像
admin创始人

打造最大的seo交流社区

上一篇:热烈祝贺我司代写泉州建筑项目可行性研究报告通过政府发改委批复(转载):泉州网站优化
下一篇:怎么提高wifi速度?:网络优化方法

发表评论