持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第16天,点击查看活动详情
一、自动装箱和封箱
- 示例讲解
public static void main(String[] args) {
Integer a=3;
Integer b=3;
Integer e=6;
Long f=6L;
Integer c=321;
Integer d=321;
System.out.println(a==b); //true
System.out.println(c==d); //false
System.out.println(e==(a+b)); //true
System.out.println(e.equals((a+b))); //true
System.out.println(f==(a+b)); //true
System.out.println(f.equals((a+b))); //false
}
"=="在不遇到算术运算的情况下不会自动拆箱,equals 不处理数据转型的关系。
当等于的两边都是包装器类型,比较的是对象,而如果其中一边是表达式,那么比较的就是值。
把一个基本类型赋值给 Object,他会自动进行装箱。
二、编译器和解释器
- 解释器(Interpreted Mode):快速的解释代码,省去编译的时间立即可以执行
- 编译器(Compiled Mode):可以编译成本地代码,执行的效率更高
- 使用-Xint 可以强制运行于解释模式
- 使用-Xcomp 可以强制运行于编译模式
解释执行节约内存,编译执行提升效率
5.程序中出现了空循环会被虚拟机优化消除掉
三、代码优化
如该代码:
int value;
final int get(){
return value;
}
public void foo(){
y=b.get();
z=b.get();
sum=y+z;
}
优化后:
int value;
final int get(){
return value;
}
public void foo(){
y=value;
sum=y+y;
}
1. 公共子表达式消除
举例说明:
int d=(c*b)*12+a+(a+b*c);
因为 cb 和 bc 结果是一样的,所以不用计算两次 可以被视为:
int d=E*12+a+(a+E);
根据代数化简优化,还能优化为
int d=E*13+a*2;
2. 数组边界检查消除
循环变量访问数组时,只要通过数据流分析循环变量的取值范围在区间之中,就可以去掉数组的上下界检查
2.1 隐式异常处理 如果有一个判断为空的表达式,值基本上都是不为空的。
if(foo!=null){
}else{
throw new NullPointException();
}
可以优化成这样:
try{
return foo;
}catch(Exception e){
throw new NullPointException();
}
这样就减少了每次的 if 判断,如果 foo 基本都不是 null
3.方法内联
简单来说就是 a 方法调了 b 的方法,就直接把 b 方法复制出来放在 a 里面,避免方法之间的真实调用。
4.逃逸分析
这不是一种代码优化,而是为其他优化提供分析数据。 如果一个对象在方法中被定义后,除了被外部方法使用,还有可能作为入参被其他方法调用,这个叫做方法逃逸。 如果一个类变量被其他线程访问,这个叫线程逃逸。
如果这个对象不会逃逸,那么可以对这个对象做一些高效的优化:
- 栈上分配:
因为对象都是分配内存在堆上的,等不用了垃圾回收机制再去整理和回收,这些都会耗费时间。如果是分配在栈上,对象随着栈桢的出栈而销毁。减轻垃圾回收的压力。
-
标量替换:
不能再拆散的数据叫标量,如基本类型和指针。如果一个对象不会被外部访问,那么他可以被拆为标量,当这个方法被执行的时候就可以不用创建对象,而改为创建这些标量,这样除了可以让这些数据在栈上外,还能进行其他优化
-
参数
-XX:+DoEscapeAnalysis 开启逃逸分析
-XX:+PrintEscapeAnalysis 查看分析结果
-XX:+EliminateAllocations 开启标量替换
-XX:+PrintEliminateAllocations 查看标量替换
-XX:+EliminateLocks 开启同步消除