4.22 错误优化策略

Wesley13
• 阅读 900

本博客来自我的新书Java系统性能优化(暂定名),也欢迎阅读我的新书 《Spring Boot 2 精髓 》

4.22.1 final无法帮助内联

有一个过时规则,“在java的getter和setter方法中经量使用final关键字,以支持内联“,比如

public final String getUserName(){
    return this.userName;f
}

在Java中,final关键字可以用来修饰类、方法和变量,我们在第三章了解到final在并发的时候,修饰变量得时候具有的语义同volatile一样,内存可见性和禁止重排序。 final修饰的方法的时候,表示子类不能覆盖此方法。早期的Java版本,final关键字还可以提醒虚拟进行内联,但现在是否内联,不再需要使用final关键字。Aleksey在他的论文里,验证了final关键字对于方法是否内联并没有直接联系,The Black Magic of (Java) Method Dispatch,有兴趣的可以自己看一下,同样有一个JMH工程可以自己下载下来测试分析一下

关于内联,参考第8章JIT优化

4.22.2 subString 内存泄露

较早的Java性能优化书指出String.subString容易造成内存泄露,主要原因是JDK版本的subString方法,会复用String的数组,并没有为新的字符串生成一个新的char数组,这样,如果原来的String特别长,那么新返回的String所占用的空间也会特别大。JDK6以后已经不再subString的时候复用char数组了,而是改成重新生成一个数组,我们再第二章看到构造一个String,会重新生成一个字符串数组value

private final char value[];
public String(char value[], int offset, int count) {
      .....
    this.value = Arrays.copyOfRange(value, offset, offset+count);
}

4.22.3 循环优化

有一种说法,嵌套循环中,嵌套循环应该遵循“外小内大”的原则,这样性能才会高,这种说法给出了俩个例子,第一个是外大内小

stratTime = System.nanoTime();
for (int i = 0; i < 100_000_00; i++) {
    for (int j = 0; j < 10; j++) {

    }
}
endTime = System.nanoTime();
System.out.println("外大内小耗时:"+ (endTime - stratTime));

外小内大

stratTime = System.nanoTime();
for (int i = 0; i <10 ; i++) {
    for (int j = 0; j < 10000000; j++) {
    }
}
endTime = System.nanoTime();
System.out.println("外小内大耗时:"+(endTime - stratTime));

俩个代码片段循环同样次数,但从测试结果看后者远大于前者,也就是嵌套循环外小内大的性能高于外大内小。

这种说法忽略了JIT会做DEAD-CODE消除,JIT判断循环对程序不会有任何影响而消除了循环体, 导致了结果测试不准,如果使用JMH测试,如下,就会发现嵌套循环结果一样

//ForDeadCodeTest.java
@Benchmark
public long test(Blackhole hole) {
  long startTime = System.nanoTime();
  int i=0,j=0;
  for ( i = 0; i < 100_000_00; i++) {
    for ( j = 0; j < 10; j++) {
      hole.consume(j);
    }
    hole.consume(i);
  }

  Long endTime = System.nanoTime();
  return endTime-startTime+i+j;
}


@Benchmark
public long tes2(Blackhole hole) {
  long startTime = System.nanoTime();
  int i=0,j=0;
  for ( i = 0; i <10 ; i++) {
    for ( j = 0; j < 100_000_00; j++) {
      hole.consume(j);
    }
    hole.consume(i);
  }
  Long endTime = System.nanoTime();
  return endTime-startTime+i+j;
}
//测试基准,空函数
@Benchmark
public long base(Blackhole hole) {
  long startTime = System.nanoTime();

  Long endTime = System.nanoTime();
  return endTime-startTime;
}

这里使用了JMH提供的Blackhole函数来防止出现代码消除情况,这种测试最后证明,俩种循环性能没有区别

Benchmark                       Mode     Score    Units              
c.i.c.c.ForDeadCodeTest.base    avgt     0.000    ms/op              
c.i.c.c.ForDeadCodeTest.tes2    avgt    56.007    ms/op              
c.i.c.c.ForDeadCodeTest.test    avgt    50.228    ms/op              

4.22.4 循环中捕捉异常

一种说法是应该在循环体外捕捉异常,而不要在循环体内,理由try catch 代价较大。

for(int i=0;i<size;i++){
  try{

  }catch(Exception ex){

  }
}

如上代码,这种说法建议改成循环体外

try{
  for(int i=0;i<size;i++){

  }
}catch(Exception ex){
}

实际上,循环体内使用try catch方式对性能几乎没什么影响,不需要关注在循环体内还需循环体外。按照自己业务需要正确使用try catch就行了。

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Wesley13 Wesley13
3年前
java系统优化中的位操作优化
本博客来自我的新书《Java系统性能优化》(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Fitem.jd.com%2F12742086.html"《Java系统性能优化》")的第四章15节,也欢迎阅读我的的经典书《SpringBoot2精髓》(https://www.o
Stella981 Stella981
3年前
Opencv中Mat矩阵相乘——点乘、dot、mul运算详解
Opencv中Mat矩阵相乘——点乘、dot、mul运算详解2016年09月02日00:00:36 \牧野(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Fme.csdn.net%2Fdcrmg) 阅读数:59593
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
3年前
Android蓝牙连接汽车OBD设备
//设备连接public class BluetoothConnect implements Runnable {    private static final UUID CONNECT_UUID  UUID.fromString("0000110100001000800000805F9B34FB");
Wesley13 Wesley13
3年前
Java性能优化
本博客来自我的新书Java性能优化(暂定名),第5章的Java代码优化技巧节选2,也欢迎阅读我的新书《SpringBoot2精髓》(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Fwww.kancloud.cn%2Fxiandafu%2Fspringboot2inpra
Stella981 Stella981
3年前
Google地球出现“无法连接到登录服务器(错误代码:c00a0194)”解决方法
Google地球出现“无法连接到登录服务器(错误代码:c00a0194)”解决方法参考文章:(1)Google地球出现“无法连接到登录服务器(错误代码:c00a0194)”解决方法(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Fwww.codeprj.com%2Fblo
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
11个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这