JVM性能魔术技巧

HotSpot是我们众所周知和喜爱的JVM,是Java和Scala汁流淌的大脑。 多年来,许多工程师对其进行了改进和调整,并且在每次迭代中,其代码执行的速度和效率都接近本机编译代码。 duke01-e1369743413155

JIT(“即时”)编译器是其核心。 该组件的唯一目的是使您的代码快速运行,这是HotSpot如此受欢迎和成功的原因之一。

JIT编译器实际上是做什么的?

在执行代码时,JVM会收集有关其行为的信息。 一旦收集了有关热方法的足够统计信息(默认阈值为10K调用),编译器就会启动,并将该方法的与平台无关的“慢”字节码转换为自身的优化,精简,平均编译版本。

一些优化是显而易见的:简单的方法内联,清除无效代码,用本机数学运算替换库调用等。请注意,JIT编译器不会就此停止。 这是它执行的一些更有趣的优化:

分而治之

您使用以下模式多少次:

StringBuilder sb = new StringBuilder("Ingredients: ");for (int i = 0; i < ingredients.length; i++) {if (i > 0) {sb.append(", ");}sb.append(ingredients[i]);
}return sb.toString();

也许这个:

boolean nemoFound = false;for (int i = 0; i < fish.length; i++) {String curFish = fish[i];if (!nemoFound) {if (curFish.equals("Nemo")) {System.out.println("Nemo! There you are!");nemoFound = true;continue;}}if (nemoFound) {System.out.println("We already found Nemo!");} else {System.out.println("We still haven't found Nemo : (");}
}

这两个循环的共同点是,在这两种情况下,循环都会做一件事一段时间,然后从某个角度开始做另一件事。 编译器可以发现这些模式,并将循环分成多个案例,或“剥离”几次迭代。

让我们以第一个循环为例。 if (i > 0)行在一次迭代中从false开始,并且从那一点开始始终计算为true 。 为何每次都要检查状况? 编译器将编译该代码,就像这样编写:

StringBuilder sb = new StringBuilder("Ingredients: ");if (ingredients.length > 0) {sb.append(ingredients[0]);for (int i = 1; i < ingredients.length; i++) {sb.append(", ");sb.append(ingredients[i]);}
}return sb.toString();

这样,即使某些代码可能在进程中重复,冗余的if (i > 0)也将被删除,因为速度就是它的全部。

生活在边缘

空检查是一丁点的。 有时null对于我们的引用是有效值(例如,指示缺少值或错误),但有时为了安全起见,我们添加了null检查。

其中一些检查可能永远不会失败(就此而言,null表示失败)。 一个经典的示例将包含一个断言,如下所示:

public static String l33tify(String phrase) {if (phrase == null) {throw new IllegalArgumentException("phrase must not be null");}return phrase.replace('e', '3');
}

如果您的代码运行良好,并且从未将null作为l33tify的参数l33tify ,则断言将永远不会失败。

在多次执行此代码而没有进入if语句的主体之后,JIT编译器可能会乐观地认为此检查很有可能是不必要的。 然后它将继续编译该方法,将检查全部丢弃,就好像是这样写的:

public static String l33tify(String phrase) {return phrase.replace('e', '3');
}

这可以显着提高性能,这在大多数情况下可能是纯粹的胜利。

但是,如果那个幸福道路的假设最终被证明是错误的呢?

由于JVM现在正在执行本机已编译的代码,因此null引用不会导致模糊的NullPointerException ,而是导致实际的,苛刻的内存访问冲突。 JVM是它的低级生物,它将拦截产生的分段错误,进行恢复,并进行反优化处理-编译器不能再假设null检查是多余的:它重新编译该方法,这次使用null检查。

虚拟精神错乱

JVM的JIT编译器与其他静态编译器(如C ++编译器)之间的主要区别之一是,JIT编译器具有动态运行时数据,决策时可以依靠该数据来运行。

方法内联是一种常见的优化方法,在该方法中,编译器采用一个完整的方法并将其代码插入另一个程序中,以避免调用方法。 在处理虚拟方法调用(或动态调度 )时,这会有些棘手。

以以下代码为例:

public class Main {public static void perform(Song s) {s.sing();}
}public interface Song { void sing(); }public class GangnamStyle implements Song {@Overridepublic void sing() {System.out.println("Oppan gangnam style!");}
}public class Baby implements Song {@Overridepublic void sing() {System.out.println("And I was like baby, baby, baby, oh");}
}// More implementations here

该方法perform可能被执行数百万次,每一次方法的调用sing发生。 调用是昂贵的,尤其是诸如此类的调用,因为调用需要根据s的运行时类型每次动态选择要执行的实际代码。 在这一点上,内联似乎是一个遥不可及的梦想,不是吗?

不必要! 执行后, perform几千次,编译器可能会决定,根据其收集的统计数据,该调用的95%的目标的一个实例GangnamStyle 。 在这些情况下,HotSpot JIT可以执行乐观优化,以消除虚拟的sing调用。 换句话说,编译器将为这些代码生成本机代码:

public static void perform(Song s) {if (s fastnativeinstanceof GangnamStyle) {System.out.println("Oppan gangnam style!");} else {s.sing();}
}

由于此优化依赖于运行时信息,因此即使它是多态的,它也可以消除大多数sing调用。

JIT编译器还有很多技巧,但是这些只是一些技巧,可让您了解当我们的代码由JVM执行和优化时的幕后故事。

我是否能帮助?

JIT编译器是面向简单人员的编译器; 它旨在优化简单的编写,并搜索出现在日常标准代码中的模式。 帮助您的编译器的最好方法是不要太努力地帮助它-只需编写代码即可。

参考:来自Takipi博客的JCG合作伙伴 Niv Steingarten的JVM性能魔术技巧 。

翻译自: https://www.javacodegeeks.com/2013/06/jvm-performance-magic-tricks.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/368169.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

mysql 10个日期,MySQL自学篇(10)——日期函数

MySQL自学篇(十)——日期函数日期和时间函数(1)获取当前日期的函数和时间的函数CURDATE()和CURRENT_DATE()函数&#xff0c;获取当前日期select current_date(),curdate(),curdate()0;curdate()0 表示将当前时间转化为数值型CURTIME()和CURRENT_TIME()获取当前时间select cur…

python-flask-请求源码流程

启动先执行manage.py 中的 app.run() class Flask(_PackageBoundObject):   def run(self, hostNone, portNone, debugNone, **options):from werkzeug.serving import run_simpletry:#run_simple 是werkzeug 提供的方法&#xff0c;会执行第三个参数 self()run_simple(ho…

正则表达式强化,爬虫练习

re模块下的常用方法 import re ret re.findall(\d(\.\d)?, 1.232.34)   print(ret) 结果&#xff1a; [.23,.34] # findall的正则表达式里面有分组(),()里面的内容优先显示 ret re.findall(\d(?:\.\d)?, 1.232.34)print(ret)    结果&#xff1a;…

Linux LVM管理

LVM(Logical Volume Manager)逻辑卷管理是在Linux2.4内核以上实现的磁盘管理技术。它是Linux环境下对磁盘分区进行管理的一种机制。 本文内容&#xff1a; 创建和管理LVM扩容LVM分区一、创建和管理LVM 要创建一个LVM系统&#xff0c;一般需要经过以下步骤&#xff1a; 1、 创建…

USB OTG插入检测识别

一 USB引脚一般四根线&#xff0c;定义如下&#xff1a; 为支持OTG功能&#xff0c;mini/micro usb接口扩展了一个ID引脚&#xff08;第4脚&#xff09; A设备端ID脚接地&#xff0c;则初始状态为Host&#xff0c;例如PC和支持OTG设备做主设备时 B设备端ID脚悬空&#xff0c;默…

CSS3与页面布局学习笔记(三)——BFC、定位、浮动、7种垂直居中方法

一、BFC与IFC 1.1、BFC与IFC概要 BFC&#xff08;Block Formatting Context&#xff09;即“块级格式化上下文”&#xff0c; IFC&#xff08;Inline Formatting Context&#xff09;即行内格式化上下文。常规流&#xff08;也称标准流、普通流&#xff09;是一个文档在被显示…

Java垃圾回收(2)

并行清理 今天&#xff0c;我们介绍了并行GC的工作原理。 具体来说&#xff0c;这是在Eden上运行Parallel Scavenge收集器&#xff0c;在Tenured一代中运行Parallel Mark and Sweep收集器的组合。 您可以通过传递-XX&#xff1a; UseParallelOldGC来获得此选项&#xff0c;尽管…

Navicat Premium创建MySQL存储过程

1、使用Navicat Premium打开创建函数向导&#xff0c;操作&#xff1a;连接名——数据库——函数——新建函数 2、选择过程——输入存储过程参数——完成&#xff08;这一步可以不填写参数&#xff0c;编写存储过程代码的时候设置参数&#xff09; 3、按照要求完成存储过程代码…

CSS3与页面布局学习笔记(二)——盒子模型(Box Model)、边距折叠、内联与块标签、CSSReset

一、盒子模型&#xff08;Box Model&#xff09; 盒子模型也有人称为框模型&#xff0c;HTML中的多数元素都会在浏览器中生成一个矩形的区域&#xff0c;每个区域包含四个组成部分&#xff0c;从外向内依次是&#xff1a;外边距&#xff08;Margin&#xff09;、边框&#xff…

mysql中将某个字段做计算,mysql创建计算字段使用子查询教程

作为计算字段使用子查询使用子查询的另一方法是创建计算字段。假如需要显示 customers表中每个客户的订单总数。订单与相应的客户ID存储在 orders 表中。为了执行这个操作&#xff0c;遵循下面的步骤。(1) 从 customers 表中检索客户列表。(2) 对于检索出的每个客户&#xff0c…

Android GreenDao使用教程

一、Greendao简介 Greendao是一款用于数据库创建与管理的框架&#xff0c;由于原生SQLite语言比较复杂繁琐&#xff0c;使得不少程序员不得不去学习SQLite原生语言&#xff0c;但是学习成本高&#xff0c;效率低下&#xff0c;所以不少公司致力于开发一款简单的数据库管理框架&…

Java垃圾回收(1)

这是有关垃圾收集&#xff08;GC&#xff09;的系列文章中的第一篇。 我希望能够涵盖整个系列过程中的理论知识以及热点虚拟机中的所有主要收集器。 这篇文章仅说明什么是垃圾回收&#xff0c;以及不同回收器共有的元素。 我为什么要在乎&#xff1f; 您的Java虚拟机可以为您管…

少锁定Java对象池

自从我写任何东西以来已经有一段时间了&#xff0c;我一直在忙于我的新工作&#xff0c;该工作涉及在性能调整方面做一些有趣的工作。 挑战之一是减少应用程序关键部分的对象创建。 尽管Java随着时间的推移改进了GC算法&#xff0c;但垃圾回收打h一直是Java的主要难题。 Azul是…

php数据库postgresql,PHP 操作 PostgreSQL数据库

1.要让PHP支持PostgreSQL&#xff0c;就需要重新编译PHP&#xff1b;./configure --prefix/usr/local/php5 --with-apxs2/usr/local/apache2/bin/apxs --with-mysql/usr/local/mysql --with-config-file-path/usr/local/php5 --with-zlib --enable-mbstringall --with-mysql…

uestc summer training #2

A 增广 #include<bits/stdc.h> using namespace std; const int MAXN 1000000 10; vector<int> g[MAXN]; int a[MAXN], b[MAXN], sz[MAXN], cnt[MAXN]; bool mg[MAXN], vis[MAXN]; int n, m; bool dfs(int u, int f -1) {if (g[u].empty()) //如果当前数没有位…

mysql有实例名这个概念,MySQL的一些概念笔记

1.MySQL Server、MySQL实例、MySQL数据库MySQL数据库指的是实际存在的物理操作系统文件的集合&#xff0c;也可以指逻辑数据的集合。为了访问、处理数据&#xff0c;我们需要一个数据库管理系统&#xff0c;也就是MySQL Server(也称为MySQL服务器)。MySQL实例指的是MySQL进程及…

python基础学习笔记(十三)

re模块包含对 正则表达式。本章会对re模块主要特征和正则表达式进行介绍。 什么是正则表达式 正则表达式是可以匹配文本片段的模式。最简单的正则表达式就是普通字符串&#xff0c;可以匹配其自身。换包话说&#xff0c;正则表达式’python’ 可以匹配字符串’python’ 。你可以…

OD debug matlab,OllyDebug基本使用方法

OD是逆向过程中最好的动态调试工具&#xff0c;这次来记录学习笔记。(特别鸣谢石总)1、OD的工作界面最开始要学的就是界面的使用N了吧&#xff0c;这里分各个框来解释下&#xff1a;列举各个框用处&#xff1a;可以看到下面一框框东西&#xff1a;这些一时半会用不到&#xff0…

设计模式:策略

这次我想谈谈策略设计模式 。 通过这种方式&#xff0c;我开始撰写有关行为设计模式的文章。 这些模式表示对象之间的某些交互模式&#xff0c;以使代码更灵活且组织得更好。此方法的最本质点是对象之间的松散耦合。 当您的应用程序中有多个实现目的的实现时&#xff0c;应使用…

本地搭建WordPress (XAMPP环境)

1&#xff0c;XAMPP是一个流行的PHP开发环境&#xff0c;官网下载&#xff1a; https://www.apachefriends.org/zh_cn/index.html 然后安装。 官方介绍&#xff1a;XAMPP是最流行的PHP开发环境 XAMPP是完全免费且易于安装的Apache发行版&#xff0c;其中包含MariaDB、PHP和Pe…