第八章软件构造的性能——性能优化的代码调优

是的!我们这节又要说设计模式了!不过没以前那么难哦,我是认真的!

1. 代码调优策略与过程(Code-Tuning Strategies and Process)

代码调优并不是为了修复bug,而是对正确性的代码进行修改以提高其性能。(通常都是些小规模的变化)

关于调优的几点说明

  • 调优不会减少代码行数(代码行数与性能之间无必然联系)
  • 不要猜原因,而应该要有明确的优化目标
    通过度量发现程序热点与瓶颈(通过上节的工具),代码调优建立在对程序性能的精确度量的基础之上,当程序做过某些调整后,要重新分析,并重新了解需要优化的性能瓶颈,微小的变化能导致优化的方向大不相同。
  • 不要边写程序边调优
    在没有完整的程序前,无法获知性能瓶颈。在开发阶段调优,更容易忽视其他更重要的质量指标。
    性能从不是追求的第一目标,正确性才是!
  • 不是性能优化的第一选择

代码调优的过程:

  1. 备份!!!!!!!!!!!!!!!(这才是第一步!!血与泪的教训嗷!!!)
  2. 通过度量分析发现代码热点瓶颈
  3. 分析原因,评判代码调优的必要性
  4. 调优
  5. 每次调优都要重新度量
  6. 如果无效果或者负效果则回滚到步骤1

2. 常见的低效来源(Common Sources of Inefficiency)

  • I/O
  • Paging
  • Operators
  • Object creation
  • GC
  • All perspectives of your code
  • ……

3.对象创建的调优与复用(Code Tuning for Object Creation and Reuse)【含代码调优的设计模式】

1. 单例模式(Singleton Pattern)

某些类在应用运行期间只需要一个实例可以采用这种设计模式。

基本思想:程序员一般需要的时候就new一个对象,导致创建多个object。然而我们可以强制客户端只能创建一个object实例,避免因为new操作所带来的时空性能(尤其是GC)的损失,也便于复用。

具体方法:设置静态变量来储存单一实例对象,将构造器修改关键字变为private,从而是客户端无法new。在构造器中new新的实例,提供静态方法来获取单一实例对象。

恩,还是栗子实在:

第八章软件构造的性能——性能优化的代码调优

此时进一步提升性能,只有在需要的时候才会new出来,而非提前构造出来。

2.轻量模式(Flyweight Pattern)

解决问题栗子:如果文本编译器中的“字符”,同一个字符会重复出现多次,代表同样的内容,但字体字号等不同。那么我们就可以采用这种模式优化。

该模式中允许在应用中不同部分共享使用objects,降低大量对象带来的时空代价。

先来说一下内部状态与外部状态:

  • 内部特征:不管在什么场合使用该object,内部特征都不变
  • 外部特征:不是固定的,需要在不同场合分别指派/计算其值

还是来看个例子吧(工厂生产大小颜色不同,但是形象相同的外星儿人):

第八章软件构造的性能——性能优化的代码调优

第八章软件构造的性能——性能优化的代码调优

其实还是很简单的,现在来说一下其与单例模式的区别吧:

  • 单例模式:不区分各个场合下的不同表现形式,统一用一个实例来表示。
  • 轻量模式:同一个事物,具有多种不同的表现形式,在对象层面的复用比单例模式更加灵活

轻量模式在外部特征不同,内部特征相同的时候可以复用,这样节省了CPU和内存。

单例模式是只有一个(通常是可变的)类的实例。它经常用于多线程环境中,以使用单个实例和“查看”相同的状态来方便所有线程。

最后值得一提的是,虽然轻量模式外部特征可以变化,但他是不可变类型,原因很简单,就是因为他在类之中已经定义好了,就算你修改外部特征,只要有相同的内部特征,那么这就是一个实例对象,就像上面的例子,大大的绿外星人和大大的蓝外星人所指的对象不都是LargeAlien嘛/p>

3. 原型模式(Prototype Pattern)

在这种设计模式中是通过克隆的方式,而非new来创建对象。(因为直接new成本太高,尤其是需要与外部I/O、网络、数据库打交道的时候,new一个图很可怕的呀!!!)

没有栗子都是空话:

第八章软件构造的性能——性能优化的代码调优

第八章软件构造的性能——性能优化的代码调优

对象拷贝:

第八章软件构造的性能——性能优化的代码调优

这是浅拷贝的一个例子,可以看见其只复制了最外层的对象,引用的内层对象是相同的,也就是说我修改了红色的person的address,蓝色的person的address也会发生变化。

第八章软件构造的性能——性能优化的代码调优

怎么样不是超可爱!!卡哇伊呐……这货原来是个二哈,看起来挺吓人,其实尼玛这不就是个空接口嘛!!!

4. 对象池模式(Object Pool Pattern)

对象复用:

时刻记住new是一个很巨大的性能代价。很多时候,对象不用就直接扔掉,需要在创建是一种巨大的浪费。所以对象复用要求就是不要扔掉对象,留着以后用嘛……

对象池模式的根本思想就是对象复用,如果这个对象我们以后还会用到,那我们为啥不把他存起来呢/p>

当然也是有缺点的,对于原本要被GC的对象,现在要留在pool中,内存自然会浪费一些,不过这就是用空间换时间的算法思想啊……

栗子就不给了,因为实在没什么说的,随随便便建个List或者Set什么的存起来就可以称之为对象池模式了,具体大家自己把握哦!

最后提一下,其实前面提到的单例模式与轻量模式本质上就是对象池,不过有点变化而已,细想想也能理解,单例模式把一个个相同的对象压缩为一个对象,自然成立。轻量模式则是把内在特征相同的对象都压缩为一个对象,也是体现了对象复用的思想。

5. 规避垃圾回收 (Avoiding GC)

核心思想:减少创建对象的数量,避免GC代价。

简单的例子:

第八章软件构造的性能——性能优化的代码调优

你们猜第一个输出和第二个输出是什么/p>

Answer:true、false。

怎么样意思吧!另外还要注意的是字符串常量池其实就是堆中分配的一块空间。

结束啦onono……我们现在再来看看和String类型差不多的数据对象Integer(这个更有意思哦!):

我们来看以下代码:

怎么样不是想摔键盘尼玛是啥啊

第一个和第二个输出很好理解,这两个对象指向两个空间肯定不相等啊!那么第三个呢不成……Integer这家伙也跟JDK申请了VIP也拥有了一个专属的常量池过如果要是那样第四个输出为啥是false

其实嘛,上面的回答之猜对了一半,Integer确实跟JDK有交易,但是可能因为钱少有给过她一个专属的常量池,不过……给了点额外的小东西:我们来看一下源码(秘密在于这个Integer.valueOf这个静态方法上):

什么个IntergerCache是什么东西接着往下找!

我去……一个-128到127的缓存!这回明白了吧。这里可以理解为建了一个[-128,127]范围的常量池!当取127的时候他会直接将引用指向池中地址,而128这个位于边界外的悲惨的家伙,就没那么幸运了。所有都引用都会指向堆中的一个新分配的地址。

大家感兴趣可以看看其他的基本对象类型是什么样的接看源码就可以,Boolean也很有意思哦!

5. 其他的代码调优方法

就简单说说吧!

逻辑:

这两种哪个更好呢案是第二个,第二个中如果程序发现x<=5了,那么他就不会在往下判定了。省了一步比较哇。

循环:

比如在数组中查找一个数据,可以用一个boolean的标志变量,如果找到就修改他然后break;

第八章软件构造的性能——性能优化的代码调优

优化方法就是,加一个判断条件,如果找到break;

这些就不在多说了,都是些平时写代码的的小技巧,没什么条理,唯有靠平时的经验与汗水!

Ahhh……好像说了很不得了的话,诶嘿嘿……第八章到现在就已经说完了。当然正如第一章所说我现在也是在处于一个复习阶段,所以时间比较紧,第九章的内容呢由于不是考点,所以会在考试之后在给大家讲解。下一章我们来谈一谈第十章——多线程哇!

来源:琴弦上的南柯合浦

声明:本站部分文章及图片转载于互联网,内容版权归原作者所有,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

上一篇 2018年5月18日
下一篇 2018年5月18日

相关推荐