关于Android内存优化方向探讨,来看看这篇 [复制链接]

2019-10-28 11:12
kengsirLi 阅读:333 评论:0 赞:0
Tag:  内存优化

一、前言

最近复习对以往项目中和学习中一些内存优化的方法进行下探讨和汇总。 虽然现在Android设备的内存越来越大,4GB内存手机已经相当普片了,但是只有有效的控制好内存才能将你的应用性能发挥到极致。所以控制好内存现在依然是Android应用中一个重要的技术指标。

开篇之前我们先说说内存.内存已经是我们很熟悉的概念了,但是你能说出手机内存和电脑内存的区别吗?手机内存之间有差异吗?内存是否大就好?

  • 什么是手机内存?

从本质上看两者是相同的,电脑上用的是DDR内存,而移动设备上的是LPDDR内存。LPDDR的英文全称为Low Power Double Data Rate,LP即为低功耗,专门用于移动式的电子产品。相较于PC领域的DDR4内存,LPDDR4形态的内存更省电。

  • 手机内存的差异?

现在主流的运行内存分别有LPDDR3、LPDDR4以及LPDDR4X.

关于Android内存优化方向探讨,来看看这篇

从上图可以看出LPDDR4的性能要比LPDDR3高出一 倍,而LPDDR4X相比LPDDR4工作电压更低,所以也比LPDDR4省电20%-40%。当然图中的数据是标准数据,不同的生成 厂商会有一些低频或者高频的版本,性能方面高频要好于低频

  • 手机内存是否大就好?

其实从上面一点我们就能得出结论。 如果一个用8GB LPDDR4X的手机性能一般是优于 12GB LPDDR3手机的。 但是内存并不是一个孤立的概念,它跟操作系统、应用生态这些因素都有关。 相信大家也对几年前的IPhone6 1GB的运行内存就能吊打4-6GB的Android手机还印象深刻。同样的内存,AndroidQ系统性能就会比Android4。0好。封闭规范的IOS系统就会比开放的Android系统好。

二、常见误区

一般大家对手机内存都有一个比较粗略的概念,就是分堆和栈,但实际上还是复杂得多。

关于Android内存优化方向探讨,来看看这篇

  • 对象只要小于内存空间即可加载?

我曾经遇到一个问题,在加载一个5MB的图片到界面时忘记压缩出现了OOM,但当我查看日志时发现可用堆内存明明还大于5MB,为什么就OOM呢?

后面我知道了堆内存其实还分新生代、老年代、永久代,各会占据一定空间如上图, 日志里看到的了大于5MB其实是新老内存共同的结果.当遇到超大对象 时,会直接将超大对象跳过新生代放置到老年代中.实际上老年代空间里已经不足5MB空间了.就算老年代空间足够如果GC是CMS(每个厂商实现略有不同,一般是混合的算法),那么只会标记清理,并不会压缩,所以内存会碎片化,同时可能出现浮游垃圾.即使老年代空间大于5MB,也会出现 没有连续空间供该对象使用.

PS:系统给每个应用分配的空间是有限的.当内存达到一定的阀值也会报OOM.

  • 所以即使内存空间足够也要注意,大资源的使用.那内存越少越好?

这也是不少人有的误区之一,甚至有人当内存是洪水猛兽,用得越少越好,这样容易优化过度产生其他问题.现在手机的发展内存越来越多,如果只有一个具体的数值,做硬指标其实是没有必要的.APP是否占用过多的内存,跟设备、性能、和当时的情况也有关.可以让高端设备使用更多的内存,做到针对设备性能的好坏使用不同的内存分配和回收策略。

三、内存优化方向

  • 内存分级优化

要做到针对设备进行优化处理,需要一个良好的架构支撑,架构需要支持以下几点:

  1. 设备分级: 使用类似device-year-class的策略对设备分级,对于低端机用户可以关闭复杂的动画,或者是某些功能;使用 565格式的图片,使用更小的缓存内存等。在现实环境下,不是每个用户的设备都跟我们的测试机一样高端,在开发过程我 们要学会思考功能要不要对低端机开启、在系统资源吃紧的时候能不能做降级
  2. 缓存管理:我们需要有一套统一的缓存管理机制,可以适当地使用内存;当"系统有难"时,也要义不容辞地归还.我们可以 使用OnTrimMemory回调,根据不同的状态决定释放多少内存.对于大项目来说,可能存在几十上百个模块,统一缓存管 理可以更好地监控每个模块的缓存大小.
  3. 进程模型:一个空的进程也会占用10MB的内存,而有些应用启动就有十几个进程,甚至有些应用已经从双进程保活升级到 四进程保活,所以减少应用启动的进程数、减少常驻进程、节制的保活,对低端机内存优化非常重要.
  4. 安装包大小: 安装包中的代码、资源、图片以及so库的体积,跟它们占用的内存有很大的关系.一个80MB的应用很难在 512MB内存的手机上流畅运行.这种情况我们需要考虑针对低端机用户推出轻量版本,例如QQ音乐HD、快手极速版、今日头条极速版都是这个思路.
  • Bitmap优化

图片资源内存一般占APP总内存很大一部分,所以做内存优化永远无法避开图片内存这个"永恒主题"。 即使把所有的Bitmap都放到Native内存,并不代表图片内存问题就完全解决了,这样做只是提升了系统内存利用率,减少了 GC带来的一些问题而已。 那我们该如何优化图片内存呢?我推荐以下两种方法:

1。统一图片库

图片内存优化的前提是收拢图片的调用,这样我们可以做整体的控制策略。例如低端机使用565格式、更加严格的缩放算法, 可以使用Glide、Fresco或者采取自研都可以。而且需要进一步将所有Bitmap。createBitmap、BitmapFactory相关的接口也一并收拢。

2.统一监控

在统一图片库后就非常容易监控Bitmap的使用情况了,这里主要有两点需要注意.

  • 大图片监控: 我们需要注意某张图片内存占用是否过大,例如⻓宽远远大于View甚至是屏幕的⻓宽。在开发过程中,如果 检测到不合规的图片使用,应该立即弹出对话框提示图片所在的Activity和堆栈,更快发现并解决问题.在灰度 和线上环境下可以将异常信息上报到后台,我们可以计算有多少比例的图片会超过屏幕的大小,也就是图片的"超宽率".
  • 分析图片总内存: 通过收拢图片使用,我们还可以统计应用所有图片占用的内存,这样在线上就可以按不同的系统、屏幕分辨 率等维度去分析图片内存的占用情况.在OOM崩溃的时候,也可以把图片占用的总内存、Top N图片的内存都写到崩溃日志中,帮助我们排查问题.

讲完设备分级和Bitmap优化,我们发现架构和监控需要两手抓,一个好的架构可以减少甚至避免我们犯错,而一个好的监控 可以帮助我们及时发现问题.

  • 内存泄漏

内存泄漏简单理解就是没有及时的回收不用的内存,排查和解决内存泄漏也是内存优化无法避开的工作之一。

内存泄漏主要分两种情况,一种是同一个对象泄漏,还有一种情况更加糟糕,就是每次都会泄漏新的对象,可能会出现几百上 千个无用的对象。

很多内存泄漏都是框架设计不合理所导致,各种各样的单例满天⻜,MVC中Controller的生命周期远远大于View.优秀的框架 设计可以减少甚至避免程序员犯错,当然这不是一件容易的事情,所以我们还需要对内存泄漏建立持续的监控。

1. Java内存泄漏: 建立类似LeakCanary自动化检测方案,至少做到Activity和Fragment的泄漏检测.在开发过程,我们希望 出现泄漏时可以弹出对话框,让开发者更加容易去发现和解决问题.内存泄漏监控放到线上并不容易,我们可以对生成的 Hprof内存快照文件做一些优化,裁剪大部分图片对应的byte数组减少文件大小。比如一个100MB的文件裁剪后一般只剩下 30MB左右,使用7zip压缩最后小于10MB,增加了文件上传的成功率

2. OOM监控: 美团有一个Android内存泄露自动化链路分析组件Probe,它在发生OOM的时候生成Hprof内存快照,然后通过 单独进程对这个文件做进一步的分析.不过在线上使用这个工具⻛险还是比较大,在崩溃的时候生成内存快照有可能会导 致二次崩溃,而且部分手机生成Hprof快照可能会耗时几分钟,这对用户造成的体验影响会比较大.另外,部分OOM是因为 虚拟内存不足导致,这块需要具体问题具体分析.

3.Native内存泄漏监控: 在 WeMobileDev的一篇文章《微信Android终端内存优化实践》中,微信也做了一些监控方案上面的尝试.

4。 针对无法重编so的情况: 使用了PLT Hook拦截库的内存分配函数,其中PLT Hook是Native Hook的一种方案.然后重定向到我们自己的实现后记录分配的内存地址、大小、来源so库路径等信息,定期扫描分配与释放是否配 对,对于不配对的分配输出我们记录的信息。

5。 针对可重编的so情况: 通过GCC的"-finstrument-functions"参数给所有函数插桩,桩中模拟调用栈入栈出栈操作;通过ld 的“–wrap”参数拦截内存分配和释放函数,重定向到我们自己的实现后记录分配的内存地址、大小、来源so以及插桩记录的 调用栈此刻的内容,定期扫描分配与释放是否配对,对于不配对的分配输出我们记录的信息.

  • GC监控

在实验室或者内部试用环境,我们也可以通过Debug。startAllocCounting来监控Java内存分配和GC的情况,需要注意的是这个 选项对性能有一定的影响,虽然目前还可以使用,但已经被Android标记为deprecated。 通过监控,我们可以拿到内存分配的次数和大小,以及GC发起次数等信息。

关于Android内存优化方向探讨,来看看这篇

上面的这些信息似乎不太容易定位问题,在Android 6.0之后系统可以拿到更加精准的GC信息。

关于Android内存优化方向探讨,来看看这篇

需要特别注意阻塞式GC的次数和耗时,因为它会暂停应用线程,可能导致应用发生卡顿。我们也可以更加细粒度地分应用场景统计,如登陆、启动、主业务等关键场。


我来说两句
您需要登录后才可以评论 登录 | 立即注册
facelist
所有评论(0)
领先的中文移动开发者社区
18620764416
7*24全天服务
意见反馈:1294855032@qq.com

扫一扫关注我们

Powered by X3.2© 2001-2019 ( )

彩票高賠率好平台 鑫彩网彩票计划群 山东十一运夺金 新利彩票计划群 海南4+1 顺发彩票计划群 极速赛车是国家开的吗 印象彩票计划群 湖北快3开奖 盛通彩票计划群