原创

调优-Java代码层优化(借助字节码分析问题)

7、Java代码层优化(借助字节码分析问题)

7.1 jvm字节码指令与javap

javap -help
用法: javap <options> <classes>
其中, 可能的选项包括:
  -help  --help  -?        输出此用法消息
  -version                 版本信息
  -v  -verbose             输出附加信息
  -l                       输出行号和本地变量表
  -public                  仅显示公共类和成员
  -protected               显示受保护的/公共类和成员
  -package                 显示程序包/受保护的/公共类
                           和成员 (默认)
  -p  -private             显示所有类和成员
  -c                       对代码进行反汇编
  -s                       输出内部类型签名
  -sysinfo                 显示正在处理的类的
                           系统信息 (路径, 大小, 日期, MD5 散列)
  -constants               显示最终常量
  -classpath <path>        指定查找用户类文件的位置
  -cp <path>               指定查找用户类文件的位置
  -bootclasspath <path>    覆盖引导类文件的位置

代码在 com.jiangjiesheng.javaOptimizationAndDebug.javacode.bytecode.ToGenerateByteCode.java

选中ToGenerateByteCode.java,执行Build > Compile 'ToGenerateByteCode.java' ,找到class文件:\target\classes\com\jiangjiesheng\javaOptimizationAndDebug\javacode\bytecode

打开cmd命令行

javap -verbose ToGenerateByteCode.class > ToGenerateByteCode.class.txt 

#生产的文件在 export/7th-javacode/ToGenerateByteCode.class.txt

7.2 基于栈的架构

avatar

相关文档 https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html

7.3 i++与++i

代码在 com.jiangjiesheng.javaOptimizationAndDebug.javacode.SelfAdd.java

avatar

小结论:

  • java中i++与++i的效率应该没有区别。

7.4 字符串拼接+

代码在 com.jiangjiesheng.javaOptimizationAndDebug.javacode.StringAdd.java

注意每次拼接都是都会new一个StringBuilder

7.5 Try-Finally

public static String f1() {
    String str = "hello";
    try{
        return str;
    }
    finally{
        str = "imooc";
    }
}

System.out.println(f1()); // 打印 "hello"

更多参考 《已备份-JAVA-专题-try catch finally-执行顺序的验证说明》

7.6 String Constant Varialbe

代码在 com.jiangjiesheng.javaOptimizationAndDebug.javacode.Constant.java

com.jiangjiesheng.javaOptimizationAndDebug.javacode.StringConstant.java

final关键字在编译成字节码时会与优化

7.6 常用代码优化方法

  1. 尽量重用对象,不要循环创建对象,比如for循环字符串拼接

  2. 容器类初始化的时候指定长度:

    List<String> collection = new ArrayList<String>(5);
    Map<String, String>map = new HashMap<String, String>(32);
    
  3. ArrayList随机遍历快,LinkedList(双向链表)添加删除快

  4. 集合遍历尽量减少重复计算

    for(int i=0,len=collection.size();i<len;i++) {}
    
  5. 使用Entry遍历Map

    for (Map.Entry<String, String> entry : map.entrySet()) {
         String key = entry.getKey();
         String value = entry.getValue();
    }
    
  6. 大数组复制用System.arraycopy()

  7. 尽量使用基本类型而不是包装类型

    Integer i1 = 100;
    Integer i2 = 100;
    System.out.println(i1 == i2); // true 
    Integer i3 = 1000;
    Integer i4 = 1000;
    System.out.println(i3 == i4);// false 
    
    Integer.IntegerCache中定义的缓存高位为127,超过这个数,就会new Integer。
    
  8. 不要手动调用System.gc()

  9. 及时消除过期对象的引用,防止内存泄漏

    代码在 com.jiangjiesheng.javaOptimizationAndDebug.javacode.Stack.java

  10. 尽量使用局部变量,减小变量的作用域

  11. 尽量使用非同步的容器ArrayList VS Vector

    Vector的很多方法加上synchronized,速度慢,线程安全。

  12. 尽量减小同步的作用范围,synchronized方法 VS 代码块

  13. ThreadLocal缓存线程不安全的对象,SimpleDateFormat

  14. 尽量使用延迟加载

    单例模式 参考《JAVA-线程安全的单例模式》

public class Singleton {//synchronized代码块锁+双重检查
  private static volatile Singleton instance = null;
  private Singleton() {
  }
  public static Singleton getInstance() {
      if (null == instance) {
          synchronized (Singleton.class) {
              if (null == instance) { //1
                  instance = new Singleton();
              }
          }
      }
      return instance;
  }

}

// valotile作用:内存可见性、禁止指令重排序
// 结论:线程安全、绝对单例
  1. 尽量减少使用反射,加缓存

  2. 尽量使用连接池、线程池、对象池、缓存

  3. 及时释放资源,I/O流、Socket、数据库连接

  4. 慎用异常,不要用抛异常来表示正常的业务逻辑

  5. String操作尽量少用正则表达式

    replace、replaceAll、split

  6. 日志输出注意使用不同的级别

  7. 日志中参数拼接使用占位符

    log.info("orderId:" + orderId); //不推荐 有拼接
    log.info("orderId:{}",orderId); //推荐
    
正文到此结束
本文目录