浅聊Android性能优化~_android应用在低性能设备的优化,移动客户端开发工程师

mData = data;

}
}

通过持有内存的引用,来代替拷贝内存。那么可能有读者有疑问:那我们是不是以后都通过持有引用的方式就可以了?并不是的,还是得根据业务的内容来决定。我们这里直接持有了相机缓存的引用,那么我们必须将数据处理操作设置为同步操作,并在处理结束后解除引用,否则会造成数据错误

在本流程中,Frame属于框架层接口。对于框架的设计,我们可以将业务层传递的byte数组,做一次拷贝,这是最安全的。不管上层传递的byte数组是否复用、是否释放等,都不会造成错误,但同时会带来一定的性能损耗。而设计为直接持有上层byte数组,意味着业务方必须了解接口参数的意义,懂得byte数组参数是被框架直接持有,如有必要,需要在外部做数据拷贝。这降低了一定的接口易用性,但也带来了更好地性能表现。另一种折中的解决方案,是创建两个不同的接口:拷贝与不拷贝,让用户决定使用哪个接口,但这也会为接口带来更高的复杂性。

最后我们来总结一下:

  1. 跟踪核心数据的处理流程,例子中是视频图像帧,记录数据发生拷贝、内存分配、运算等地方,重新思考是否有更好的解决方案,来减少计算和内存成本。
  2. 如果发生在接口层的优化,需要考虑优化的成本,是否符合场景需求。在易用性、复杂性、高性能等因素中找到平衡点。

接下来我们看第二个优化点。

优化二

android studio有一个非常好用的性能分析工具:android profile,他可以帮助我们分析运行中的cpu占用情况,以及内存的分配情况。从这些数据中我们可以去分析,我们的程序是否存在问题,是否有优化的空间。

继续案例一中的场景,在开发中,利用这个工具完成了许多性能优化,或者说是bug的排查。这里主要讲两个:内存抖动和内存泄露。具体工具的使用方式可以移步官方文档 Android Profiler ,这里我主要介绍使用这个工具解决问题的思路。

首先第一个:内存抖动。android profile可以在运行时,查看内存的占用情况,在开发过程中我使用工具查看了一下运行时内存情况,类似下图:(图源网络)

ps:下面相关的图像我均采用网络图片代替,嗯,,因为我懒得去重现一次场景再记录图像(手动狗头)

内存出现频繁增长与垃圾回收,图像呈现锯齿状。内存的频繁申请与释放,会损耗大量的性能,最终导致的结果就是我们的应用卡顿。android profile具有的另一个功能是记录函数的内存申请大小,如onCreate函数申请了多少内存,剩余多少内存等。通过这个功能,我查询了一下其在运行时内存分配所在的函数以及对象情况,如下:(图源网络)

工具详细记录了所创建的对象,如上面两个图:byte数组占大多数内存分配;createSubDecor函数占大多数的内存分配。那么我们拿到这些信息之后,就可以去到对应的方法进行排查。

在我的项目,我的原因主要是,在java层每帧都拷贝一次数据,导致不断开辟内存,但是却使用一次就丢弃。场景一的优化之后,减少了这次拷贝即解决了这个问题。

第二,内存泄露。检测内存泄露最好的方式就是:不断重进场景,观察内存增量。如果每次进入、退出之后,内存都有增量,则非常可能发生了内存泄露。在当时的检测中,发现运行时内存不断增长,即使手动垃圾回收也无济于事,最后导致OOM程序崩溃。这很明显就是发生了内存泄露。通过记录内存申请记录,发现是在jni,在c++线程中创建了java对象,使用完成后未删除局部引用,导致对象无法被虚拟机回收(在c++线程结束后,对象才会被回收)。

借助类似的类似的工具,可以查看程序对于资源的使用情况,也是非常方便帮助我们做性能优化的。

优化三

第三个优化,是学习了android在屏幕刷新机制上的思路,来提升整体的帧率性能。还回到我们工作的项目中来。我们的项目框架主要的能力就是渲染数据帧,但其对输入有一个要求:在上一帧渲染完成之前,不允许下一帧输入,否则会被限流节点丢弃数据。因此在原来的程序是这样的:

横向代表时间线,竖直线代表帧的输入,蓝色箭头代表框架sdk正在渲染数据帧,此时无法接受新的帧输入

观察上面的图像,框架处理数据的时间比帧输入更长,因此当第二帧输入的时候,第一帧还没处理完成,此时第二帧被丢弃。但是,当第一帧处理完成的时候,此时第三帧数据尚未到达,框架sdk进入空闲状态。

为了提高整体的处理帧率,我们需要让框架sdk时刻保持运行状态。因此我在这里学习android的渲染机制,加上双缓冲。

  1. 输入的数据缓存到双缓冲中进行保存,直接覆写到back内存中,如果front内存没有数据,则交换前后缓冲区
  2. 框架sdk从front区读取数据,并交换前后缓冲区

增加了缓存之后,可以保证框架sdk时刻处于运行当中,提高整体输出帧率,如下图:

这次优化的核心思路在于:充分利用cpu、内存等资源,来实现我们需要的效果。前面我们说的,都是如何节省资源,降低消耗,但都是在保证相同的输出效果,或者可接受损失的情况下。而这次性能优化,则是充分利用我们的硬件资源,实现更好的表现效果。对于渲染库而言,帧率表现,也是其性能表现的一个方面。

但此类型的优化也有他的代价:增加cpu与内存的负载。当评估下来之后,觉得这些资源的付出,值得换来帧率的提升,那么这次优化就是有意义的。反之,在一些低性能低下的机器,内存本身就非常紧张,双缓冲需要的内存代价就太大了。需要结合具体的业务情况来做判断。

优化四

做android开发的读者都知道,我们不能在主线程做耗时操作,会直接导致界面卡顿。因此大多数的操作我们会选择放在子线程去运行。多线程并行处理数据,可以提高整体的处理效率。在我们的项目中,对数据帧的处理通常是多节点的,如下:

节点的处理之间,有严格的先后关系,也有无关的可并行关系。对于并行关系的节点,我们可以创建多个线程,进行并行处理,提高处理时间,如下:

将处理2和处理3进行并行处理,再分别输出。这是最基本的优化方案,但事实上,在实际开发中还会遇到一些其他的问题。

处理2节点与处理3并行之后,需要付出的代价有:增加一个线程,处理增加线程切换的代价;增加数据占用的内存;增加对cpu的负载等等。换来的效率提升是否值得也是需要综合评估。

在项目中,我处理成并行是有效果的。原因是处理2与处理3耗时在几十ms,而线程切换带来的损耗小于1ms,内存占用低,因此对于数据的传递我是采用指针传递的,不涉及内存的拷贝。综合评估下,这是一个值得的优化,可以降低整体流程几十ms的时间。

你以为这就结束了吗?在测试中又发现了新的问题。在低端机器中,本身cpu已经跑满了,增加了线程之后,非但没有提升效率,反而线程切换的损耗带来了效率的下降。cpu负载这一代价,导致此优化是无效的。因此,该优化仅在中高端机器上开启。

线程是一把双刃剑,运用得好,可以为我们带来很大的效率提升,但同时也要注意需要付出的代价,避免反向优化。

总结

好,以上就是近段时间,我的一些关于性能优化的经验,咱们再来总结一下性能优化的思路:

  1. 性能优化是跟着具体的业务场景去实现的,跟踪核心数据、核心流程,如图像帧处理流程,分析每个步骤的处理是否合理,是否有优化的空间。
  2. 利用工具分析运行时的内存与cpu等资源情况,发现可能存在的内存泄露、内存抖动、cpu占用过高等问题。
  3. 性能优化可以是保证效果降低资源的使用,也可以是充分利用资源,提高程序的表现效果。
  4. 在做出优化的决策前,要综合评估当前的环境因素,分析优化需要付出的代价,避免反向优化。

性能优化过程中,可以参考以下的具体建议:

  1. 尽量减少数据拷贝
  2. 尽量减少内存申请,使用缓存池来代替反复申请与释放
  3. 平衡线程的数量与并行处理的任务耗时之间的关系,找到最佳平衡点
  4. 注意代码细节的性能问题,如遍历次数、内存占用量等,不同的编程语言也会有不同的特性,通过练习算法题目可以增强性能意识

性能优化并不是一个高深莫测的技能,而是需要我们在开发过程中时刻注意的问题,少一次拷贝、少一次遍历,都能让我们的程序性能更好。但我们无法在开发初期则达到最佳的性能表现,需要我们阶段性进行整体的性能检测与优化,来排查代码中存在的性能问题。

练习算法题目是个不错的方式,能够提高自己对性能的意识,增强自己性能优化能力,写出更加强壮的代码。不同的编程语言有自己的特性,需要结合自己的语言去学习,如java的垃圾回收、c++的主动释放等。我认为,面向api写代码大家都会,而真正决定差距的,是代码的设计与性能。


为了帮助到大家更好的全面清晰的掌握好性能优化,准备了相关的学习路线以及核心笔记(还该底层逻辑):https://qr18.cn/FVlo89 大家可以进行参考学习:

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数HarmonyOS鸿蒙开发工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年HarmonyOS鸿蒙开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上HarmonyOS鸿蒙开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新

如果你觉得这些内容对你有帮助,可以添加VX:vip204888 (备注鸿蒙获取)
img

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

视频,并且会持续更新**

如果你觉得这些内容对你有帮助,可以添加VX:vip204888 (备注鸿蒙获取)
[外链图片转存中…(img-jStkm3qu-1712780557473)]

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值