性能分析(一)

认真工作中.jpg

简述性能分析与调优

czfshine

程序的运行总要消耗系统资源的,无论是CPU,内存还是磁盘IO。我们编写高质量的代码除了易用性可扩展性之外,还应注重资源的使用情况。

性能分析可以分析你的代码在用例下各部分所消耗的资源情况,而性能调优是对分析结果进行解析,并有方向的针对代码进行优化。

本文使用我最近在弄的一个聊天记录分析程序进行示例,简单说下怎么进行性能分析和调优。

怎样进行性能分析与调优

先讲下背景,这个项目分析聊天记录的数据库,解析生成Java对象。代码使用Java和Kotlin

,性能分析软件使用JProfiler,安装过程我就省略了,不是本文的重点。

下面开始讲怎么进行性能分析。

首先是编写测试用例,和TDD(测试驱动开发)里面的测试用例不一样的是,我们这个用例主要针对你想进行性能分析的代码,保证该部分代码的常用情况都包含在内,而且测试数据量得完整一些。

这里我测试对所有数据进行读入的部分代码。

编写测试用例后点击IDEA的Profile按钮开始进行性能分析。

这里的性能分析分为两个方向,一是对CPU使用情况进行分析,看哪些方法最耗时,并对其进行优化。二是分析内存使用情况,看有没有内存泄漏。

性能分析的原理大概是利用反射(或类似机制)给各个方法增加统计代码,并收集统计信息。显然这样做会影响性能。JProfiler默认提供两个选项,一个是使用全部的特性对代码进行分析,可以很详细得出各个对象与方法的使用情况,这种方法对性能影响最大。第二个选项是只对CPU进行简单分析,这种方法得到的数据较少,不过同样对性能影响较小。

我们这里先选用第二选项。

之后可以对我们需要统计的细节进行配置,网上教程都有,就不赘述了。

之后将会运行测试代码,并收集信息。我们可以在JProfiler的监控面板看到内存,cpu的使用情况。

等代码运行结束点击工具栏的按钮让它停止记录。

CPU性能分析

看Hot Spots 可以看到一个方法的总调用时间与调用次数。

我们先分析一下前几个的性能热点,

第一个read是在等待用户输入,所以时间长,不用理。

第二个是将字符串中的特殊符号(XML)进行转义的,下面会分析。

第三和第五是数据库的,大部分时间应该是在文件IO和安全性上面,现在先不管。

第四的contains下面进行分析。

第六个listfiles是文件IO的,慢是正常。

第七个,代码里大量使用哈希表,所以hash函数调用频次多,占用资源大也正常。

接下来的方法占用时间太少就不分析了。

在左侧面板可以点击Call Tree 查看调用树。

调用树显示各个方法的调用层次与运行时间,我们主要分析占用大多数时间或运行时间异常的方法。

看上面那个,Talker.addMessage是将一条聊天记录加到对应的发送者内部的HashSet里面的,理论上复杂度应该是O(1)的,不应该占用那么多的时间。看他调用的子方法,大部分时间花在contains 上面了,这个方法是O(n)的,所以问题出在这。

先分析原因:

因为这个项目支持从多数据库导入聊天记录,所以这里使用contains是为了防止重复消息的。

再看看能不能解决:

其实本项目使用单例工厂模式,对每一条相同的消息,都只构造一个实例。而且这个Talker.addMessage方法是在Message的工厂函数内被调用的,这样已经可以保证一条消息只会被加入一次,所以这里的contains是多余的,分支不会被执行。

验证一下:

使用全部数据(多个数据库)执行,可以发现println 语句并不会被执行,也就是说上面的分析是正确的。

解决方法:

删掉if语句,这样可以节省近5%的时间(其余4%是计算对象Hash的时间,无法消除的).

结果如下:

第二个是XML转义的

使用这个函数的原因的要将聊天记录导出成docx文件,本质上就是输出成xml,所以要对特殊字符进行转义。不过代码中的转义是写在基类里面的,其实并不需要对所有消息的内容进行转义,那些图片,表情的消息就不需要,只需对文本消息转义即可。而且,文本消息的内容长度所占的比重不到1%。

CPU分析的就到这,内存分析的请听下回分解。

干货多多,

关注科联自科部

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20181009G1TSC800?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券