这波性能优化,太炸裂了!(中)

简介: 这波性能优化,太炸裂了!(中)

ROXY_FACTORY 就是一个 static 的字段。

上面的代码的字节码大概是这样的:

image.png

通过字节码你可以看到,首先有一个 getstatic 调用,来获得静态字段 PROXY_FACTORY 的值。

还有一个 invokevirtual 指令的调用,对应的就是 ProxyFactory 实例的 getProxyPreparedStatement() 方法:

15: invokevirtual #69  // Method com/zaxxer/hikari/proxy/ProxyFactory.getProxyPreparedStatement:(Lcom/zaxxer/hikari/proxy/ConnectionProxy;Ljava/sql/PreparedStatement;)Ljava/sql/PreparedStatement;

这个地方有什么优化空间呢?

作者把代码修改成了这样:

image.png

其中 ProxyFactory 是通过 Javassist 生成的。

所以你去看 ProxyFactory 源码,全是空实现,

image.png

它真正的实现逻辑,是对应源代码的这个类,就不具体展示了,有兴趣的可以下来看看:

com.zaxxer.hikari.util.JavassistProxyFactory

然后,把 getProxyPreparedStatement 方法做成了 static。

然后字节码就变成了这样:

image.png

  • getstatic 指令消失了
  • invokevirtual 被替换成了 invokestatic 调用,这样更加容易被JVM优化。
  • 最后,可能第一眼没有注意到的是,堆栈大小从 5 减少到 4 。这是因为在 invokevirtual 的情况下,ProxyFactory 的实例被隐含地传递到了堆栈中(也就是 this 对象),而且在调用 getProxyPreparedStatement() 时,还有一个额外的从堆栈中弹出的操作。

第 1,3 点应该问题不大。大家都能明白是怎么回事。

但是这个第二点:invokevirtual 被替换成了 invokestatic 调用,这样更加容易被JVM优化。

说真的,我第一次看到的时候大概是这样的:

image.png

为啥啊?

invokevirtual 和 invokestatic 是干啥的我倒是还记得。

但是 invokestatic 的性能会更好一点吗?

于是我带着这个问题去翻了《深入理解JVM虚拟机》,没有直接找到答案。

但是还是有意外收获的。就是写下了这篇文章:《报告!书里有个BUG》

不然你觉得我为什么会突然翻到书里面的这一部分,都是有契机的。

image.png

虽然,书里面没有直接把答案写出来,但是在相关部分有这样的一段话:

image.png

我理解一下就是 invokevirtual 指令,需要查询虚方法表才能确定方法的直接引用。

而 invokestatic 在类加载的时候,就可以从符号引用转成直接引用。

这样看来,invokestatic 确实是优于 invokevirtual 的。

那么问题又来了。

类加载的过程是什么?

加载、验证、准备、解析、初始化。

invokestatic 是在哪个过程搞事情的?

肯定是解析阶段哈,朋友们。

解析阶段,就是 JVM 将常量池内的符号引用替换为直接引用的过程。

扯远了,说回来。

上面只是我的一点猜测,我相信肯定不止我一个人看了作者的“兔子洞”文章后关于 invokevirtual vs invokestatic 这一块有疑问。

于是,我去查了一圈。

果不其特么的然。(抱歉爆粗了,但是我确实找了很久。)

找到了这个链接,链接的前半部分和我的问题一模一样:

https://github.com/brettwooldridge/HikariCP/issues/464


image.png

后面那一段 Additionally 很好理解。

就是前面说的,静态调用少一个堆栈,在运行时就少一个推/拉操作,这进一步提高了性能。

主要是前面这段,有亿点点难懂。

他说:简而言之,JVM 在做内联调用的时候,即使是单态的内联,它也必须安装一个 trap(陷阱),以防另一个实现出现,并将调用转变为多态。

这个 trap 的设置和清除给调用增加了一点开销。

怎么样,懵不懵逼?

其实,他这句话,我个人理解,说的就是 Java 的动态分派,聊的就是 JVM 的 CHA(Class Hierarchy Analysis,类型继承关系分析) 技术。

答案就写在《深入理解Java虚拟机(第三版)》的 417 页,翻去吧:

微信图片_20220428152914.jpg

目录
相关文章
|
2月前
|
缓存 负载均衡 网络协议
作者推荐 | 高并发挑战?试试这些架构优化篇技巧,让你的系统焕发新生!
作者推荐 | 高并发挑战?试试这些架构优化篇技巧,让你的系统焕发新生!
49 1
|
8月前
|
消息中间件 缓存 Java
牛掰!阿里人用7部分讲明白百亿级高并发系统(全彩版小册开源)
高并发 提到“高并发”相信你们应该都不会感到陌生!此时你脑中应该会浮现好多有关高并发的:业务急剧增长、电商购物、电商秒杀、12306抢票、淘宝天猫各种活动等;都是需要用到高并发的,那么如何去设计一个高并发系统抵挡这些冲击呢? 其实这也是一道很常见的面试题,但是大多数应聘者都不知如何回答,从何答起。对于一个Java程序员来讲,,更关注的是不是系统架构层面的呢?从原本的定时秒杀,到现在各种活动的预热、拼团、定金膨胀、百亿补贴、跨店满减以及更复杂的组合优惠,让用户摸不到头脑,虽然这些都扰乱了用户购买的节奏,但是也一直保持着持续升温的状态。
|
11月前
|
设计模式 缓存 Java
吃透阿里2023版Java性能优化小册后,我让公司系统性能提升了200%
性能优化可以说是很多一线大厂对其公司内高级开发的基本要求(其中以Java岗最为显著)。其原因有两个:一是提高系统的性能,二是为公司节省资源。两者都能做到,那你就不可谓不是普通程序员眼中的“调优大神了”。 那么如何成为一名“调优大神”呢?
|
11月前
|
设计模式 缓存 Java
好家伙!阿里新产Java性能优化(终极版),涵盖性能优化所有操作
上月公司来了一位大佬,入职不到一周就把公司现有项目的性能优化了一遍,直接给公司节省了一半的成本。 一问情况,才知道这位仁兄也是一路被虐过来的。去年年底被裁,本以为自己技术还行,看了一段时间面经,复习了基础知识,就开始投大厂简历。阿里最先给他面试机会,结果没能扛过三面,然后是各种大大小小的公司,在实际面试中被碾压得翻不了身。整整一个半月,一个offer都没拿到,最后针对性的恶补,才入职了我司。
|
负载均衡 监控 测试技术
认清性能问题
首先专注于业务上最需要优先修正的程序,而不是从全局调优来改善性能。要重视全局的性能表现,但解决问题要从细节和业务最需要的环节入手。
认清性能问题
|
存储 缓存 分布式计算
Java性能调优的七大方向
能优化根据优化的类别,分为业务优化和技术优化。业务优化产生的效果也是非常大的,但它属于产品和管理的范畴。同作为程序员,在平常工作中,我们面对的优化方式,主要是通过一系列的技术手段,来完成对既定的优化目标。
41213 0
Java性能调优的七大方向
|
存储 缓存 运维
完爆 90% 的性能毛病,22 点通用绝招介绍(二)
完爆 90% 的性能毛病,22 点通用绝招介绍(二)
完爆 90% 的性能毛病,22 点通用绝招介绍(二)
|
存储 NoSQL 算法
完爆 90% 的性能毛病,22 点通用绝招介绍(一)
完爆 90% 的性能毛病,22 点通用绝招介绍(一)
完爆 90% 的性能毛病,22 点通用绝招介绍(一)
|
设计模式 缓存 监控
如何搞好性能优化
想必大家都晓得,程序员想要提升,性能优化这块是最重要的一点,实现同样的功能,不同的设计思路能够极大的节省服务器开销,能够更好的提高用户体验,本篇文章我们就来一起探讨一下,性能优化优化的是哪些点。
116 0
|
SQL 缓存 监控
这波性能优化,太炸裂了!(下)
这波性能优化,太炸裂了!(下)
126 0
这波性能优化,太炸裂了!(下)