调优-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 基于栈的架构
相关文档 https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html
7.3 i++与++i
代码在 com.jiangjiesheng.javaOptimizationAndDebug.javacode.SelfAdd.java
小结论:
- 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 常用代码优化方法
尽量重用对象,不要循环创建对象,比如for循环字符串拼接
容器类初始化的时候指定长度:
List<String> collection = new ArrayList<String>(5); Map<String, String>map = new HashMap<String, String>(32);
ArrayList随机遍历快,LinkedList(双向链表)添加删除快
集合遍历尽量减少重复计算
for(int i=0,len=collection.size();i<len;i++) {}
使用Entry遍历Map
for (Map.Entry<String, String> entry : map.entrySet()) { String key = entry.getKey(); String value = entry.getValue(); }
大数组复制用System.arraycopy()
尽量使用基本类型而不是包装类型
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。
不要手动调用System.gc()
及时消除过期对象的引用,防止内存泄漏
代码在 com.jiangjiesheng.javaOptimizationAndDebug.javacode.Stack.java
尽量使用局部变量,减小变量的作用域
尽量使用非同步的容器ArrayList VS Vector
Vector的很多方法加上synchronized,速度慢,线程安全。
尽量减小同步的作用范围,synchronized方法 VS 代码块
ThreadLocal缓存线程不安全的对象,SimpleDateFormat
尽量使用延迟加载
单例模式 参考《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作用:内存可见性、禁止指令重排序
// 结论:线程安全、绝对单例
尽量减少使用反射,加缓存
尽量使用连接池、线程池、对象池、缓存
及时释放资源,I/O流、Socket、数据库连接
慎用异常,不要用抛异常来表示正常的业务逻辑
String操作尽量少用正则表达式
replace、replaceAll、split
日志输出注意使用不同的级别
日志中参数拼接使用占位符
log.info("orderId:" + orderId); //不推荐 有拼接 log.info("orderId:{}",orderId); //推荐