简介

之前我们在讲Virtual call的时候有提到,virtual call方法会根据传递的参数实例的不同而进行优化,从而优化成为classic call,从而提升执行效率。

今天我们考虑一下,在virtual call中执行nullcheck的时候,如果已经知道传递的参数是非空的。JIT会对代码进行优化吗?

一起来看看吧。

一个普通的virtual call

我们来分析一下在方法中调用list.add方法的例子:

public class TestNull {

    public static void main(String[] args) throws InterruptedException {
List<String> list= new ArrayList();
list.add("www.flydean.com");
for (int i = 0; i < 10000; i++)
{
testMethod(list);
}
Thread.sleep(1000);
}
private static void testMethod(List<String> list)
{
list.get(0);
}
}

代码很简单,我们在循环中调用testMethod方法,而这个方法里面又调用了list.get(0)方法,来获取list的第一个参数。

单纯的看testMethod,这个方法是有可能抛出NullPointerException的,但是从整体运行的角度来看,因为我们的list是有值的, 所以不会抛出异常。

使用JIT Watcher看看运行结果:

先看第二个和第三个红框,我们可以看到代码先做了参数类型的比较,然后对testMethod进行了优化,这里还可以看到get方法是内联到testMethod中的。

代码优化的部分我们找到了,那么异常处理呢?如果list为空,应该怎么处理异常呢?

第一个红框,大家可以看到是一个隐式的异常处理,它重定向到1152b4f01这个地址。

第四个红框就是这地址,表示的是异常处理的代码。

普通方法中的null check

我们在上面的普通方法里面加上一个null check:

public class TestNull1 {

    public static void main(String[] args) throws InterruptedException {
List<String> list= new ArrayList();
list.add("www.flydean.com");
for (int i = 0; i < 10000; i++)
{
testMethod(list);
}
Thread.sleep(1000);
} private static void testMethod(List<String> list)
{
if(list !=null ){
list.get(0);
}
}
}

上面我们添加了一个list !=null的判断。

运行看下结果:

相比较而言,我们可以看到,代码其实没有太多的变化,说明JIT在代码优化的过程中,将null check优化掉了。

那么null check到底在什么地方呢? 看我标红的第二个框,这里是之前的异常处理区域,我们可以看到里面有一个ifnull,表明这里做了null check。

反优化的例子

上面的两个例子,我们可以看出在virtual method中,JIT对null check进行了优化。接下来我们再看一个例子,在这个例子中,我们显示的传递一个null给testMethod,然后再次循环testMethod,如下所示。

for (int i = 0; i < 10000; i++)
{
testMethod(list);
}
Thread.sleep(1000);
testMethod(null);
for (int i = 0; i < 10000; i++)
{
testMethod(list);
}

我们看下JIT的结果:

看下结果有什么不同呢?

第一,ifnull现在是显示调用的,并不包含在隐式异常中。

第二,隐式异常也不见了,因为使用显示的ifnull。

总结

JIT会根据不同的情况,对代码进行不同程度的优化,希望大家能够喜欢。

本文作者:flydean程序那些事

本文链接:http://www.flydean.com/jvm-assembly-nullcheck/

本文来源:flydean的博客

欢迎关注我的公众号:程序那些事,更多精彩等着您!

最新文章

  1. Ubuntu Server 16.04下ASP.NET Core Web Api + MySql + Dapper在 Jexus、nginx 下的简单测试
  2. 10月16日上午MySQL数据库作业设计表解析
  3. [KOJ6023]合并果子&#183;改
  4. 使用按钮控制HTML5背景音乐开关
  5. SQLServer索引
  6. Thrift 个人实战--RPC服务的发布订阅实现(基于Zookeeper服务)
  7. AFNetwork 作用和用法详解
  8. module_init宏解析
  9. windows下mysql 控制台操作
  10. Android Activity设置为全屏的方法
  11. jquery append 动态添加的元素事件on 不起作用的解决方案
  12. Oracle日志文件的管理与查看
  13. C实现类、继承、多态
  14. 软件测试的cookie测试
  15. 《Linux命令行与shell脚本编程大全》第十三章 更多的结构化命令
  16. 基于docker的 Hyperledger Fabric 多机环境搭建(下)
  17. ubuntu旧版本源失效的处理方法
  18. Android深入理解Context(一)Context关联类和Application Context创建过程
  19. [面试]volatile类型修饰符/内存屏障/处理器缓存
  20. Oracle day02 函数

热门文章

  1. java 基本语法(一) 关键字与标识符
  2. 数据可视化之powerBI基础(十四)Power BI中创建联动切片器
  3. redis(五):Redis 键(key)(python)
  4. linux专题(五):常用的基本命令(三)文件内容查看
  5. linux中无法使用vim命令
  6. 【其他-小技巧-Uipath】VB语法操作DataTable分组并求和
  7. python学习03-使用动态ua
  8. MSSQL系列 (二):表相关操作、列操作、(唯一、主键、默认、检查、外键、非空)约束、临时表
  9. echarts 踩坑 : 为什么触摸柱状图的时后柱子不见了?原来是color的锅!
  10. 1.pandas打开和读取文件