Introduction to JVM Intrinsics – JVM内部程序介绍

最后修改: 2021年 1月 23日

中文/混合/英文(键盘快捷键:t)

1. Introduction

1.介绍

In this article, we’re going to learn what intrinsics are and how they work in Java and other JVM-based languages.

在这篇文章中,我们将学习什么是内含物,以及它们如何在Java和其他基于JVM的语言中工作。

2. What Are Intrinsics?

2.什么是Intrinsics?

An intrinsic function is a function that has special handling by the compiler or interpreter for our programming language. More specifically, it’s a special case where the compiler or interpreter can replace the function with an alternative implementation for various reasons.

内在函数是指编译器或解释器对我们的编程语言有特殊处理的函数。更具体地说,它是一种特殊情况,编译器或解释器可以出于各种原因用另一种实现方式来替换该函数。

The programming language typically handles this by understanding that a specific method call is special, and whenever we call this method, then the resulting behavior is different. This then allows our code to look no different from normal, but the programming language’s implementation can intervene in special cases to give additional benefits.

编程语言通常通过理解一个特定的方法调用是特殊的,只要我们调用这个方法,那么产生的行为就不同。这样一来,我们的代码看起来就和正常的代码没有什么区别,但是编程语言的实现可以在特殊情况下进行干预,给予额外的好处。

The exact way that it works varies between programming languages and also between operating systems and hardware. However, because these are handled for us, we typically don’t need to know any of these details.

它的具体工作方式在不同的编程语言之间有所不同,在不同的操作系统和硬件之间也有所不同。然而,由于这些都是为我们处理的,我们通常不需要知道这些细节。

Intrinsics can give various benefits. Replacing particular algorithms with native code can make them perform better or even leverage the operating system’s specific features or underlying hardware.

内含物可以带来各种好处。用本地代码替换特定的算法可以使其性能更好,甚至可以利用操作系统的特定功能或底层硬件。

3. Intrinsics on the JVM

3.JVM上的内含物

The JVM implements intrinsics by replacing the exact method call on an exact class with an alternative version. The JVM handles this itself, so it will only work for core classes and particular architectures. It also allows only certain methods to be swapped out, rather than entire classes.

JVM通过用一个替代的版本替换一个确切的类上的确切的方法调用来实现本征。JVM自己处理这个问题,所以它只对核心类和特定的架构有效。它也只允许某些方法被替换,而不是整个类被替换。

Exactly how this works will vary between JVMs. This includes not only different versions of the JVM – Java 8 vs. Java 11, for example. This also includes different JVM targets – Linux vs. Windows, for example – and especially JVM vendors – Oracle vs. IBM. In some cases, certain command-line flags passed to the JVM can affect them.

确切地说,这在不同的JVM之间会有所不同。这不仅包括不同版本的JVM–例如,Java 8对Java 11。这也包括不同的JVM目标–例如,Linux对Windows–特别是JVM供应商–Oracle对IBM。在某些情况下,传递给JVM的某些命令行标志会影响它们。

This variety means that there’s no way to determine, based only on the application, which methods will be replaced with intrinsic and which won’t. It’ll be different based on the JVM running the application. But this can lead to surprising results in some cases – including significant performance benefits achieved simply by changing the JVM used.

这种多样性意味着没有办法仅根据应用程序来确定哪些方法会被替换成内在的,哪些不会。它将根据运行应用程序的JVM而有所不同。但这在某些情况下会导致令人惊讶的结果–包括仅仅通过改变所使用的JVM而实现的显著性能优势

4. Performance Benefits

4.性能优势

Intrinsics are often used to implement a more efficient version of the same code, for example, by leveraging implementation details of the running OS or CPU. Sometimes this is because it can use a more efficient implementation, and other times it can go as far as using hardware-specific functionality.

内含物经常被用来实现同一代码的更有效版本,例如,通过利用运行中的操作系统或CPU的实现细节。有时,这是因为它可以使用更有效的实现,而其他时候,它甚至可以使用硬件特定的功能。

For example, the HotSpot JDK has an intrinsic implementation for many of the methods in java.lang.Math. Depending on the exact JVM, these are potentially implemented using CPU instructions to do the exact calculations required.

例如,HotSpot JDK对java.lang.Math中的许多方法有一个内在的实现。根据具体的JVM,这些方法有可能使用CPU指令来完成所需的精确计算。

A simple test will demonstrate this. For example, take java.lang.Math.sqrt(). We can write a test:

一个简单的测试将证明这一点。例如,以java.lang.Math.sqrt()为例。我们可以写一个测试。

for (int a = 0; a < 100000; ++a) {
    double result = Math.sqrt(a);
}

This test is performing a square root operation 100,000 times, which takes approx 123ms. However, if we replace this code with a copy of the implementation of Math.sqrt() instead:

这个测试是在进行100,000次平方根运算,大约需要123ms。然而,如果我们用一份Math.sqrt()的实现来代替这段代码。

double result = StrictMath.sqrt(a);

This code does the same thing but executes in 166ms instead. That’s an increase of 35% by copying the implementation instead of allowing the JVM to replace it with the intrinsic version.

这段代码做同样的事情,但执行时间为166ms。通过复制实现,而不是让JVM用内在的版本来替换它,这就增加了35%。

5. Impossible Implementations

5.不可能的实施

In other cases, intrinsics are used for situations where the code can’t be implemented in Java. These are typically reserved for very low-level cases.

在其他情况下,本征用于代码不能用Java实现的情况。这些通常是保留给非常低级的情况。

For example, let’s look at the method onSpinWait() in the java.lang.Thread class. This method indicates that this thread is currently performing no work and that CPU time can be given to another thread. To implement this, it needs to work at the lowest level possible.

例如,让我们看看java.lang.Thread类中的onSpinWait()方法。这个方法表示这个线程目前没有执行任何工作,CPU时间可以给另一个线程。为了实现这一点,它需要在尽可能低的级别上工作。

The HotSpot JDK for x86 architectures implements this directly on the CPU, using the PAUSE opcode. The only other way to achieve this would’ve been to use a JNI call to native code, and the overhead involved in this would defeat the benefits of the call in the first place.

适用于x86架构的HotSpot JDK使用PAUSE操作码直接在CPU上实现了这一功能。实现这一功能的唯一其他方法是使用JNI调用本地代码,而这其中涉及的开销首先会使调用的好处失效。

6. Identifying Intrinsics in Java

6.识别Java中的Intrinsics

There is, unfortunately, no guaranteed way to identify methods that might be replaced with intrinsic versions. This is because different JVMs or even the same JVM on different platforms will do this for different methods.

不幸的是,没有保证能够识别可能被替换为内在版本的方法。这是因为不同的JVM甚至不同平台上的同一个JVM会对不同的方法进行替换。

However, when using Hotspot JVM as of Java 9, the @HotSpotIntrinsicCandidate annotation is used on all methods that may be replaced. Adding this annotation doesn’t automatically cause the method to be replaced. In reality, that happens within the underlying JVM. Instead, JVM developers know that these methods are special and to be careful with them.

然而,当从Java 9开始使用Hotspot JVM时,@HotSpotIntrinsicCandidate注解被用于所有可能被替换的方法。添加这个注解并不会自动导致该方法被替换。在现实中,这发生在底层JVM中。相反,JVM开发者知道这些方法是特殊的,要小心对待它们。

Other JVMs might handle this differently if they are identified at all. This includes the Hotspot JVM in Java 8 or older.

其他JVM可能会以不同的方式处理这个问题,如果它们被识别的话。这包括Java 8或更早的Hotspot JVM。

7. Summary

7.总结

We can’t write our programs to rely on the presence of intrinsics because there’s no way to know if they’ll be available or not on the runtime JVM. However, they are a compelling approach that the JVM can use to improve the way that programs will work.

我们不能把我们的程序写成依赖于内在因素的存在,因为我们没有办法知道它们在运行时的JVM上是否可用。然而,它们是一种引人注目的方法,JVM可以用它来改善程序的工作方式。

These intrinsics can be – and often are – added to newer versions of the JVM. This, then, allows for improvements to our already running code simply by upgrading the JVM that we’re running on, so this is another reason to ensure that we stay up-to-date with our dependencies and runtime.

这些内在因素可以–而且经常是–被添加到较新版本的JVM中。这样一来,只需升级我们所运行的JVM,就可以改进我们已经运行的代码,所以这是确保我们与我们的依赖和运行时间保持同步的另一个原因。