JIT(Just In Time)编译器, 也称即时编译器, 主要在JVM运行时期动态的做一些优化提升代码的运行速度和效率。
大家都知道, jvm运行时是通过解释器将每一条class字节码指令翻译成机器指令去执行。
JIT则不同, 它会在jvm运行时期动态的将热点代码编译成机器指令, 缓存下来. 之后每次执行这段代码时, 直接执行对应的机器码, 无需再次编译。
要注意的是, JIT并不是jvm一启动就工作, 因为它需要检测出哪些是热点代码, 所以一般需要jvm运行一段时间才开始工作。(所以有时候服务刚启动时, 会感觉很慢, 执行一段时间又感觉变快了, 可能就是这个原因
)
1、热点代码检测
一般有两种方式:
- 采样探测
定期去线程的栈顶检测, 频繁出现在栈顶的方法会被判定为热点方法。这种方式简单但是不精准, 且会受线程阻塞影响。 - 计数器探测
给每个方法或代码块创建一个计数器, 统计执行次数, 超过阈值就判定为热点代码。进行编译缓存。
另外JIT编译器还会通过逃逸分析、标量替换、栈上分配、内联优化、同步消除、锁消除等多种手段,提升执行效率。使Java程序在保证跨平台特性的同时,能够接近原生编译代码的执行效率。
2、逃逸分析
可以通过启动参数进行设置
-XX:+DoEscapeAnalysis 开启
-XX:-DoEscapeAnalysis 关闭
2.1、全局逃逸
一般发在全局变量上、或者方法的返回值上
class Test{
public static Object obj;
public void updateRes(){
obj = new Object();
}
public static Job createJob(){
Job job = new Job();
...
return job;
}
}
2.2、参数逃逸
一般发生在对象被作为参数传递代码中
class Test{
public JobDto getJobDto(){
JobDto jobDto = assemble2JobDto(jobInfo);
return jobDto;
}
public JobDto assemble2JobDto(JobInfo jobInfo){
//jobInfo对象从getJobDto方法逃逸到本方法,且未发生全局逃逸
...
return jobDto;
}
}
2.3、无逃逸
方法中的对象没有发生逃逸,对象的作用范围在一个方法体内
class Test{
public String getJobTitle(Long jobId){
JobInfo jobInfo = getJobInfo(jobId); // jobInfo对象并为作为返回值, 逃逸出方法外
String jobTitle = jobInfo.getJobTitle();
return jobTitle;
}
}
3、标量替换
如果逃逸分析确定某个对象可以被分解为多个基本类型变量(标量),那么这些变量可以直接在栈上分配,减少堆内存的占用。
class Test{
public void printNum(){
JobRate jobRate = new JobRate(20,30);
int ratePer = rate.getMaxRate() - rate.getMinRate();
}
class JobRate{
private int minRate;
private int maxRate;
}
}
这段代码经过逃逸分析后, 发现jobRate对象未发生逃逸, 且可以被拆分为标量, 那么就可以不用创建JobRate对象, 直接进行标量替换去计算
class Test{
public void printNum(){
int minRate = 20;
int maxRate = 30;
int ratePer = maxRate - minRate;
}
4、栈上分配
如果逃逸分析确定某个对象不会逃逸出方法,那么这个对象可以在栈上分配内存,而不是在堆上。方法执行完毕,对象的内存立即释放,这可以避免垃圾收集器的介入,减少垃圾回收的开销。
一般发生在循环中临时对象创建时。
5、同步消除/锁消除
如果逃逸分析确定某段代码中的锁不会被其他线程访问,那么这个锁可以被消除。
class Test{
public void RedeemPrize(){
object lock = new Object();
synchronized(lock){
int accPoints = getAccPoints();
...
}
}
}
上面这段代码, 经过逃逸分析, lock对象没有发生逃逸, 且不会被其他线程访问到, 会被进行优化
class Test{
public void RedeemPrize(){
int accPoints = getAccPoints();
...
}
}
6、内联优化
将方法的调用替换为方法的具体代码,主要是为了节省方法调用时的栈开销,包括创建栈帧、读写寄存器、栈溢出检测等
class Test{
public int ratePer(int minRate, int maxRate){
return maxRate - minRate;
}
public void CommissionPayout(){
int ratePer = ratePer(20, 30);
}
}
以上代码经过JIT优化会变成
class Test{
public void CommissionPayout(){
int ratePer = 30 - 20;
}
}
标签:Java,int,代码,技术,class,JIT,逃逸,Test,public
From: https://blog.csdn.net/weixin_44541808/article/details/143774559