前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >运用AOP思想更优雅地进行性能调优

运用AOP思想更优雅地进行性能调优

作者头像
腾讯移动品质中心TMQ
发布2018-02-06 15:34:49
1.3K0
发布2018-02-06 15:34:49
举报
文章被收录于专栏:腾讯移动品质中心TMQ的专栏

在软件测试中,如果想在一个耗时严重的操作中找出其耗时的瓶颈时,一般采用的方法是在每个被调用的函数中写进测试代码,在运行时打出日志。如果该操作涉及到的业务逻辑特别复杂时,插入这些测试代码不仅工作量十分巨大,而且难以维护。如果后期剔除不干净,不仅增加了无关的代码量,还会在执行时造成不必要的资源浪费。

像在手机管家的清理加速模块中,垃圾扫描这个功能的耗时是性能优化的重点,如何快速测试和分析扫描过程中的函数耗时一直是性能测试想克服的难题。但是在数以千计的函数中插入测试代码简直是一场恶梦,所以优化过程一直是不知道从何开始从何结束。这时候好想有个脚本可以跟踪调用关系,并且可以根据规则自动插入测试代码。

在继续进一步学习时,发现很多开发大牛也遇到同样的问题,他们代码中有一些公共的代码需要统一在一系列的函数运行时被调用,在经历了无数次重复的代码修改后,终于忍无可忍的他们提出了一种新的编程思想——面向切面编程(Aspect-Oriented Programming),这是一种在运行时,动态地将代码切入到类的指定方法、指定位置上的编程思想。

它是一种可以通过预编译方式和运行期间的动态代理实现的编程技术,在不修改源代码的情况下给程序统一添加某种功能,共享一个行为,主要可用来作为日志记录,性能统计,安全控制和事务处理等等。而且最重要的是,打包时可以通过不同的编译选项选择插入或者剔除测试代码,真正做到无损插桩!啊!果然很适合这种性能调优场景,赶紧学起来!

开始了解AOP

面向切面编程思想中有两个核心的步骤:

1. 在软件中挑选出来需要关注的切面关注点 (pointcut),即程序中我们选择出来的执行点的集合,选择出来之后就可以对其进行后续操作,比如性能调优这里选择了手机管家中的sdcard卡扫描这个关注点,这里可以通过通配符组合各种规则来选取一系列的函数;

2. 在切面上增加一些需要统一执行的操作(advice),比如统一给切面选取到的函数添加统计耗时的代码, 这里主要有三种类型,分别是:

(1)before : 在执行点的代码执行之前进行操作

(2)after : 在执行点的代码执行之后进行操作

(3)around :将before和after拼接在同一个执行点上,就是around操作

具体示意图如下,看不懂也没关系,下面还会有具体代码的演示。

所以怎么应用到具体工程上

AOP这么厉害,所以到底怎么应用到具体工程上。对于java、C++都已经有了对应的AOP支持版本,aspectj就是基于java易用的、功能强大的aop编程语言。在eclipse中安装AJDT插件就可以快速对工程进行插桩。

aspectJ插桩实战

在刚刚简介的基础上了解AOP的基本思想,接下来通过aspectJ实战脚本的例子深入了解下如何对你的程序进行自动插桩吧。

(1)查看运行函数:

我的程序功能很复杂,在测试CPU使用率时总发现一个现象,灭屏时进程的CPU使用率会突然升高,现有的log无法发现问题,想看看这是灭屏后程序到底有没有做什么异常操作,有没有异常调用其他不相关函数,这时候该怎么办?

用法详解:

  • a. pointcut TestPoint()表示定义了TestPoint这个切点,在切点表达式中使用execution(*deepclean..*(..))匹配所有函数名中含有deepclean字符的函数,execution代表在该函数的执行处进行操作;
  • b. before():TestPoint() 操作代表在TestPoint这个切点的执行前插入打印函数签名的代码。

用法:打完插桩包后,安装后,打开被插桩过的软件,logcat中自动输出每个清理相关函数的函数名,此时便可查看是否有异常调用

(2)定位耗时操作的性能瓶颈:

业务中有个扫描的函数,想查看在扫描执行过程中该函数调用到的每个函数运行耗时,查看耗时瓶颈,以定位最应优化的函数

pointcut 定义详解:

  • a. cflow表示跟踪scanAll()函数被调用的工作流,所以在scanAll()中调用的函数都会被我们选取到;
  • b. !within(CPUTimeTest)表示不要跟踪aspectj脚本测试类中的代码,避免插桩后代码的自循环,其中CPUTimeTest是工程中自定义的测试类名(这个是使用cflow关键字对函数进行跟踪时的必加项!);
  • c. && TestPoint() 保证跟踪的函数都是clean相关的函数,避免引入不必要测试日志,TestPoint()定义详情参照上个例子。

advice 定义详解:

  • a. 使用around()函数将测试函数的函数体包围在测试代码中,被测函数的函数体为Object obj= proceed();
  • b. 使用安卓自带的debug函数获取线程运行耗时:Debug.threadCpuTimeNanos()(debug类中有许多性能监控获取接口,如内存使用率、CPU使用率等,可以按照自身需要切换不同监控数据)
  • c. 插桩后代码实际执行顺序为:记录进入函数时的startTime,运行函数本体,记录函数执行完的endTime,输出两者之间的时间差

用法:安装插桩包后,通过logcat收集日志中各个函数耗时,得到扫描过程中每个函数过程中的耗时和被调用次数,查看扫描瓶颈。如果输出函数过多,还可以使用HashMap对每个函数的调用次数和总耗时进行统计,最后输出最终结果。

(3)输出异常情况的调试信息:

测试过程中想监控一个函数,如果其耗时(或者其他指标)超过预定的最大值,则为异常情况,想输出异常情况下函数的调用行数和调用堆栈

用法详解:

  • a. 在上一个例子的基础上,使用if逻辑判断耗时是否是异常数值,减少输出日志的数量,更容易定位问题
  • b. 使用thisJoinPointStaticPart获取该切点的静态信息,包括被调用的文件名,行数和函数签名,方便进行定位和跟踪

用法:安装插桩包,触发业务逻辑,查看日志输出,定位异常路径

获取AOP的更多信息

由于篇幅的局限,这里只是通过一些例子简单地讲解了AOP的相关应用。作为一种新的程序设计模式,AOP还蕴含着更多的能力,不仅仅适用于性能调优上,还能应用在开发上,它能将逻辑代码和处理琐碎事务的代码分离开,减少代码实现和维护的复杂度。

更多的AOP和aspectJ的学习资料可以参考下面链接:

(1)https://eclipse.org/aspectj/doc/released/adk15notebook/index.html 官方aspectJ开发者文档

(2)http://blog.csdn.net/zl3450341/article/details/7673938 详细的aspectJ语法中文讲解

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2016-09-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 腾讯移动品质中心TMQ 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
应用性能监控
应用性能监控(Application Performance Management,APM)是一款应用性能管理平台,基于实时多语言应用探针全量采集技术,为您提供分布式性能分析和故障自检能力。APM 协助您在复杂的业务系统里快速定位性能问题,降低 MTTR(平均故障恢复时间),实时了解并追踪应用性能,提升用户体验。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档