内存优化就是对内存问题的一个预防和解决,做内存优化能让应用挂得少、活得好和活得久。
挂的少:
“挂”指的是 Crash,内存问题导致 Crash 的具体表现就是内存溢出异常 OOM。
活得好:
活得好指的是使用流畅,Android 中造成界面卡顿的原因有很多种,其中一种就是由内存问题引起的。内存问题之所以会影响到界面流畅度,是因为垃圾回收(GC,Garbage Collection),在 GC 时,所有线程都要停止,包括主线程,当 GC 和绘制界面的 *** 作同时触发时,绘制的执行就春御会被搁置,导致掉帧,也就是界面卡顿。
活得久:
活得久指的是我们的应用在后台运行时不会被干掉。Android 会按照特定的机制清理进程,清理进程时优先会考虑清理后台进程。清理进程的机制就是LowMemoryKiller。在 Android 中不同的进程有着不同的优先级,当两个进程的优先级相同时,低杀会优先考虑干掉消耗内存更多的进程。也就是如果我们应用占用的内存比其他应用少,并且处于后台时,我们的应用能在后台活下来,这也是内存优化为我们应用带来竞争力的一个直接体现。
内存占用是否越少越好?
当系统 内存充足 的时候,我们可以多用 一些获得更好的性能。当系统 内存不足 的时候,我们希望可以做到 ”用时分配,及时释放“。内存优化并不能一刀切。
我们都知道,应用程序的内存分配和垃圾回收都是由Android虚拟机完成的,在Android 5.0以下,使用的是Dalvik虚拟机,5.0及以上,则使用的是ART虚拟机。
Android虚拟机Dalvik和ART
1、内存区域划分
详细请看以下两篇文章(建议全看):
java内存四大区_JVM内存区域划分
Android 内存机制
2、内存回收
垃圾收集的标记算法(找到垃圾):
垃圾收集算法(回收垃圾):
引用类型:强引用、软引用、弱引用、虚引用
对象的有效性=可达性+引用类型
JAVA垃圾回收机制-史上最容易理解看这一篇就够了
Android:玩转垃圾回收机制与分代回收策略
android中还存在低杀机制,这种情况属于系统整机内存不足,直接把应用进程杀掉的情况。
Android后台杀死系列:LowMemoryKiller原理
1、内存溢出
系统会给每个App分配内存空间也就是heap size值,当app占用的内存加上申请的内存超过这个系统分配的内存限额,最终导致OOM(OutOfMemory)使程序崩溃。
通过命令 getprop |grep dalvik.vm.heapsize 可以获取系统允许的最大
注意:在设置了heapgrowthlimit的状况下,单个进程可用最大内存为heapgrowthlimit值。在android开发中,若是要使用大堆,须要在manifest中指定android:largeHeap为true,这样dvm heap最大可达heapsize。
关于heapsize &heapgrowthlimit
2、内存泄漏
Android系统虚拟机的垃圾回收是通过虚拟机GC机制来实现的。GC会选择一些还存活的对象作为内存遍历的根节点GC Roots,通过对GC Roots的可达性来判断是否需要回收。内存泄漏就是 在当前应用周期内不再使用的对象被GC Roots引用,造成该对象无法被系统回收,以致该对象在堆中所占用的内存单元无法被释放而造成内存扒圆岩空间浪费,使实际可使用内存变小。简言之,就是 对象被持有导致无法释放或不能按照对象正常的生命周期进行释放。
Android常见内存泄漏汇总
3、内存抖动
指的是在短时间内大量的新对象被实例化,运行时可能无法承载这样的内存分配,在这种情况下就会导致垃圾回收事件被大量调用,影响到应用程序的UI和整体性能,最终可能导致卡顿和OOM。
常见情况:在一些被频繁调用的方法内不断地创建对象。例如在View 的onDraw方法内new 一些新腔慎的对象。
注意内存抖动也会导致 OOM,主要原因有如下两点:
1、Android Studio Profiler
作用
优点
内存抖动问题处理实战
理解内存抖动的概念的话,我们就能明白只要能找到抖动过程中所产生的对象及其调用栈,我们就能解决问题,刚好Android Studio 的Porfiler里面的Memory工具就能帮我们记录下我们 *** 作过程中或静止界面所产生的新对象,并且能清晰看到这些对象的调用栈。
选择Profile 中 的Memory ,选择 Record Java/Kotlin allocations,再点击Record开始记录, Record Java/Kotlin allocations 选项会记录下新增的对象。
*** 作完成之后,点击如图所示的红脑按钮,停止记录。
停止记录后,我们就可以排序(点击 Allocations可以排序)看看哪些对象或基本类型在短时间被频繁创建多个,点击这些新增的对象就可以看到它的完成的调用链了,进而就找找到导致内存抖动的地方在哪里了。
2、利用DDMS 和 MAT(Memory Analyzer tool)来分析内存泄漏
我们利用工具进行内存泄漏分析主要是用对比法:
a.先打开正常界面,不做任何 *** 作,先抓取一开始的堆文件。
b.一顿胡乱 *** 作,回到原来 *** 作前的界面。主动触发一两次GC,过10秒再抓取第二次堆文件。
c.通过工具对比,获取胡乱 *** 作后新增的对象,然后分析这些新增的对象。
DDMS作用:抓取堆文件,主动触发GC。(其实也是可以用Android Studio 的Profile里面的Memory工具来抓取堆文件的,但是我这边在利用Profile 主动触发gc 的时候会导致程序奔溃,也不知道是不是手机的问题,所以没用Android Studio的Profiler)
MAT作用:对堆文件进行对比,找到多出的对象,找到对象的强引用调用链。
以下是详细的过程:
步骤1.打开DDMS,选择需要调试的应用,打开初始界面,点击下图的图标(Dump Hprof File)先获取一次堆文件。
步骤2.对应用随便 *** 作后,回到一开始的界面,先多触发几次GC ,点击下图的图标(Cause Gc)来主动触发GC,然后再次点击 Dump Hprof File 图标来获取堆文件。
步骤3.通过Android Studio Profile 或者 DDMS dump 的堆文件无法在MAT 打开,需要借助android sdk包下的一个工具hprof-conv.exe来转换。
格式为 hprof-conv 旧文件路径名 要转换的名称;
例如:hprof-conv 2022-04-13_17-54-40_827.hprof change.hprof
步骤4.把两份堆文件导入MAT,然后选择其中第二次获取的堆文件,点击 如图所示的 Histogram查看。
步骤5.点击下图图标,Compare To Another Heap Dump ,选择另一份堆文件。
6.会得出下图所示的 Hitogram 展示,我们主要看Objects 这一列。 如下图所示 “+ 2” 则代表前面两份堆文件对比,这个对象多了两个,我们主要就是要分析这些多了出来,没有被回收的对象。
7.加入我们从增加的对象中,看到了MainActivity ,则需要从一开始打开的Hitogram 展示里面找到这个对象的调用栈。如下图所示,搜索MainActivity
8.看到下图所示解雇,然后鼠标右键点击下图红色圈圈着的MainActivity ,选择 Merger Shortest Paths to Gc Roots ,再选择 exclude all phantom/weak/soft etc.references ,就可以看到这个MainActivity 对象的强引用链,至此我们就可以找到MainActivity对象是被什么引用导致无法回收了。
3、内存泄露检测神器之LeakCanary(线下集成)
自行学习了解,接入简单,使用简单,基本可以解决大部分内存泄漏问题。
github地址 : https://github.com/square/leakcanary/
学习地址 : https://square.github.io/leakcanary/changelog/#version-22-2020-02-05
针对内存抖动的建议:
针对内存泄漏问题的建议:
针对内存溢出问题的建议(主要就是要减少内存占用):
建议参考:
深入探索 Android 内存优化(炼狱级别)
对于 优化的大方向,我们应该优先去做见效快的地方,主要有以下三部分:内存泄漏、内存抖动、Bitmap。完善监控机制也是我们的重点,能帮助我们对内存问题快速分析和处理。
参考:
深入探索 Android 内存优化(炼狱级别)
安卓手机的rom和ram区分:
ROM和RAM介绍。
ROM是英文Read Only Memory的首字母的缩写,也就是说存储器只能读不能写。 RAM是英文RandomAccess Memory的首字母的缩写,则是可以随机读写的意思。但是,在计算技术突飞猛进的这几年里, RAM和ROM的定义也发生了不少的改变。现在ROM通常指固态的存储器,或者说,不掉电。系统停止供电的时候它们仍然可以保持数据。而RAM通常都是断电电之后就没有数据的,典型的就象计算机的内存,需要系统重新启动的时候从硬盘重新载入数据。
手机上的ROM。
不过手机上的ROM和我们一般意义上定义的ROM不同,因为虽然手机上的ROM是可以储存东西,但是我们在一般情况下只能读取不能写入,这也就是为什么其叫做“只读储存器”戚友的原因,只有在特定的专业条件下,我们才可以往ROM里面写入东西。鉴于ROM的这种特殊性,很多手机的系统文件都存储在手机的ROM 里,这样在一般情况下我们就无法修改手机的系统文件,不过目前通过一些特殊的手段,我们也可以实现往ROM里面写入东西,这种情况其实也就是我们经常所说的刷机、刷系统,因此这也被大家叫做刷ROM。综上所述, 手机上的ROM是指手机系统及可安装程序的空间,ROM越大,能直接在系统里安装的程序就越多,相当于我们电脑的C盘。 当然ROM空间也是越大越好。不过现在很多程序都可以完全安装到内存卡(自从不可添加内存卡的手机出现,软件大多被安装在内置SD卡里面。甚至有些大ROM的手机都分出了足够大的DATA分区,用来存储安装程序。当然这都是题外话,我们今天要说明的是区分ROM和RAM,其他的就不在赘述了),所以这个指标对于一个手机配置来说就看来不是那么重要了,但是也不能太小,太小了,我们知道,安卓手机系统版本经常要升级,新版本有时候需要更大的ROM空间才能存储,我们选择手机的时候,看当下情况,始终就行,只是让大家知道ROM的大小和手机运行快慢没有绝对的关系。
手机上的RAM。
手机上的RAM是指系统运行及软件运行可需要的临时空间,跟电脑上的内存是相同的意思。 RAM越大,可同时运行的程序就越多,一些需要大量RAM的游戏也越流畅。同等cpu配置的情况下,RAM越大运行就越流畅。同样的道理,开机系统服务及一些软件自动后台运行,都会占用一部分RAM空间。如果厂家说明是2GB,实际开机后你看到的却远远少于2GB,这也是正常的。这个RAM是越大越好。当然,RAM越大悄碧价格肯定越贵。
手机上RAM的存储机制与特点。
再来跟大家谈谈Android系统的RAM内存分配机制,其实在用安卓手机的时候,不用太在意剩余内存,Android 上的应用是java,当然需要虚拟机,而android上的应用是带有独立虚拟机的,也就是每开一个应用就会打开一个独立的虚拟机。如果你知道java,就能更清楚这机制了。其实和java的垃圾回收机制类似,系统有一个规则来回收内存。进行内存调度有个阀值,只有低于这个值系统才会按一个列表来关闭用户不需要的东西。当然这个值默认设置得很小,所以你会看到内存老在很少的数值徘徊。但事实上他并不影响速度。相反加快了下次启动应用的速度。这本来就是 android标榜的优势之一,如果人为去关闭进程,没有太大必要。特别是使用自动关进程的软件。到这里有人会说了,那为什么内存少的时候运行大型程序会慢呢?其高运槐实很简单,在内存剩余不多时打开大型程序,会触发系统自身的调进程调度策略,这是十分消耗系统资源的 *** 作,特别是在一个程序频繁向系统申请内存的时候。这种情况下系统并不会关闭所有打开的进程,而是选择性关闭,频繁的调度自然会拖慢系统。所以,有个更改内存阀值的程序可以有一定改善。但改动也可能带来一些问题,取决于值的设定。 那么,进程管理软件有无必要呢?有的。就是在运行大型程序之前,你可以手动关闭一些进程释放内存,可以显著的提高运行速度。但一些小程序,完全可交由系统自己管理。
android后台原理。
那么,如果不关程序是不是会更耗电。 说说android后台的原理,你就明白了android的应用在被切换到后台时,它其实已经被暂停了,并不会消耗cpu资源,只保留了运行状态。所以为什么有的程序切出去重进会到主界面。但是,一个程序如果想要在后台处理些东西,如音乐播放,它就会开启一个服务。服务可在后台持续运行,所以在后台耗电的也只有带服务的应用了。这个在进程管理软件里能看到,标签是service。我们可以把带服务的进程用进程管理软件关闭就可以了。没有带服务的应用在后台是完全不耗电的,没有必要关闭这种设计本来就是一个非常好的设计,下次启动程序时,会更快,因为不需要读取界面资源,何必要关掉他们抹杀这个android的优点呢。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)