Java 8 Java11中的空方法明显比Java8慢

Java 8 Java11中的空方法明显比Java8慢,java-8,java-11,jmh,Java 8,Java 11,Jmh,我在使用1.21比较JDK 8和11的性能时遇到了一些令人惊讶的数字: Java版本:1.8.0192,供应商:Oracle公司 基准模式Cnt分数误差单位 MyBenchmark.emptyMethod avgt 25 0.362±0.001 ns/op Java版本:9.0.4,供应商:Oracle公司 基准模式Cnt分数误差单位 MyBenchmark.emptyMethod avgt 25 0.362±0.001 ns/op Java版本:10.0.2,供应商:Oracle公司 基准模式

我在使用1.21比较JDK 8和11的性能时遇到了一些令人惊讶的数字:

Java版本:1.8.0192,供应商:Oracle公司
基准模式Cnt分数误差单位
MyBenchmark.emptyMethod avgt 25 0.362±0.001 ns/op
Java版本:9.0.4,供应商:Oracle公司
基准模式Cnt分数误差单位
MyBenchmark.emptyMethod avgt 25 0.362±0.001 ns/op
Java版本:10.0.2,供应商:Oracle公司
基准模式Cnt分数误差单位
MyBenchmark.emptyMethod avgt 25 0.723±0.001 ns/op
Java版本:11.0.1,供应商:Oracle公司
基准模式Cnt分数误差单位
MyBenchmark.emptyMethod avgt 25 0.724±0.002 ns/op
OpenJDK 11和12的性能与OracleJDK 11类似。为了简洁起见,我省略了他们的数字

我知道微基准并不表示实际应用程序的性能行为。不过,我很好奇这种差异是从哪里来的有什么想法吗?


以下是整个基准:

pom.xml

package jmh;

import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;

import java.util.concurrent.TimeUnit;

@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public class MyBenchmark
{
    @Benchmark
    public void emptyMethod()
    {
    }
}

4.0.0
jmh
空方法
1.0-快照
罐子
JMH基准测试示例:Java
org.openjdk.jmh
jmh核
${jmh.version}
org.openjdk.jmh
jmh发生器
${jmh.version}
假如
UTF-8
1.21
1.8
基准
org.apache.maven.plugins
maven enforcer插件
1.4.1
强制执行版本
执行
3
org.apache.maven.plugins
maven编译器插件
3.8.0
${javac.target}
${javac.target}
${javac.target}
org.apache.maven.plugins
maven阴影插件
3.2.1
包裹
阴凉处
${uberjar.name}
org.openjdk.jmh.Main
*:*
META-INF/*.SF
META-INF/*.DSA
META-INF/*.RSA
maven清洁插件
2.6.1
maven部署插件
2.8.2
maven安装插件
2.5.2
maven jar插件
3.1.0
maven javadoc插件
3.0.0
maven资源插件
3.1.0
maven站点插件
3.7.1
maven源插件
3.0.1
maven surefire插件
2.22.0
src/main/java/jmh/MyBenchmark.java

package jmh;

import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;

import java.util.concurrent.TimeUnit;

@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public class MyBenchmark
{
    @Benchmark
    public void emptyMethod()
    {
    }
}
下面是我使用的特定于Windows的脚本。将其转换到其他平台应该很简单:

set JAVA_HOME=C:\Program Files\Java\jdk1.8.0_192
call mvn -V -Djavac.target=1.8 clean install
"%JAVA_HOME%\bin\java" -jar target\benchmarks.jar

set JAVA_HOME=C:\Program Files\Java\jdk-9.0.4
call mvn -V -Djavac.target=9 clean install
"%JAVA_HOME%\bin\java" -jar target\benchmarks.jar

set JAVA_HOME=C:\Program Files\Java\jdk-10.0.2
call mvn -V -Djavac.target=10 clean install
"%JAVA_HOME%\bin\java" -jar target\benchmarks.jar

set JAVA_HOME=C:\Program Files\Java\oracle-11.0.1
call mvn -V -Djavac.target=11 clean install
"%JAVA_HOME%\bin\java" -jar target\benchmarks.jar
我的运行时环境是:

ApacheMaven 3.6.0(97c98ec64a1fdfee7767ce5ffb20918da4f719f3;2018-10-24T14:41:47-04:00)
Maven主页:C:\Program Files\apache-Maven-3.6.0\bin\。。
默认区域设置:en_CA,平台编码:Cp1252
操作系统名称:“windows 10”,版本:“10.0”,arch:“amd64”,系列:“windows”
更具体地说,我正在运行Microsoft Windows[Version 10.0.17763.195]

您正在测量的是空基准,而不是空方法。换句话说,测量处理基准本身的最小基础结构代码。这很容易剖析,因为在热路径上只需要一些指令。JMH的
-prof perfasm
-prof xperfasm
将在几秒钟内为您提供最热门的指令

我认为这种影响是由于,见:

8u191:0.389±0.029纳秒/升 [目前为止一切顺利]

  3.60%  ↗  ...a2: movzbl 0x94(%r8),%r10d
  0.63%  │  ...aa: add    $0x1,%rbp
 32.82%  │  ...ae: test   %eax,0x1765654c(%rip) ; global safepoint poll
 58.14%  │  ...b4: test   %r10d,%r10d
         ╰  ...b7: je     ...a2
  0.31%  ↗  ...70: movzbl 0x94(%r9),%r10d    
  0.19%  │  ...78: mov    0x108(%r15),%r11  ; reading the thread-local poll addr
 25.62%  │  ...7f: add    $0x1,%rbp          
 35.10%  │  ...83: test   %eax,(%r11)       ; thread-local safepoint poll
 34.91%  │  ...86: test   %r10d,%r10d
         ╰  ...89: je     ...70
  5.64%  ↗  ...62: movzbl 0x94(%r8),%r10d    
  0.91%  │  ...6a: add    $0x1,%rbp          
 34.36%  │  ...6e: test   %eax,0x179be88c(%rip) ; global safepoint poll
 54.79%  │  ...74: test   %r10d,%r10d
         ╰  ...77: je     ...62
11.0.2:0.585±0.014 ns/op[oops,回归]

  3.60%  ↗  ...a2: movzbl 0x94(%r8),%r10d
  0.63%  │  ...aa: add    $0x1,%rbp
 32.82%  │  ...ae: test   %eax,0x1765654c(%rip) ; global safepoint poll
 58.14%  │  ...b4: test   %r10d,%r10d
         ╰  ...b7: je     ...a2
  0.31%  ↗  ...70: movzbl 0x94(%r9),%r10d    
  0.19%  │  ...78: mov    0x108(%r15),%r11  ; reading the thread-local poll addr
 25.62%  │  ...7f: add    $0x1,%rbp          
 35.10%  │  ...83: test   %eax,(%r11)       ; thread-local safepoint poll
 34.91%  │  ...86: test   %r10d,%r10d
         ╰  ...89: je     ...70
  5.64%  ↗  ...62: movzbl 0x94(%r8),%r10d    
  0.91%  │  ...6a: add    $0x1,%rbp          
 34.36%  │  ...6e: test   %eax,0x179be88c(%rip) ; global safepoint poll
 54.79%  │  ...74: test   %r10d,%r10d
         ╰  ...77: je     ...62
11.0.2,-XX:-threadlocal握手:0.399±0.048 ns/op[返回到8u性能]

  3.60%  ↗  ...a2: movzbl 0x94(%r8),%r10d
  0.63%  │  ...aa: add    $0x1,%rbp
 32.82%  │  ...ae: test   %eax,0x1765654c(%rip) ; global safepoint poll
 58.14%  │  ...b4: test   %r10d,%r10d
         ╰  ...b7: je     ...a2
  0.31%  ↗  ...70: movzbl 0x94(%r9),%r10d    
  0.19%  │  ...78: mov    0x108(%r15),%r11  ; reading the thread-local poll addr
 25.62%  │  ...7f: add    $0x1,%rbp          
 35.10%  │  ...83: test   %eax,(%r11)       ; thread-local safepoint poll
 34.91%  │  ...86: test   %r10d,%r10d
         ╰  ...89: je     ...70
  5.64%  ↗  ...62: movzbl 0x94(%r8),%r10d    
  0.91%  │  ...6a: add    $0x1,%rbp          
 34.36%  │  ...6e: test   %eax,0x179be88c(%rip) ; global safepoint poll
 54.79%  │  ...74: test   %r10d,%r10d
         ╰  ...77: je     ...62
我认为这在很大程度上是可见的,主要是在像这样的紧密循环中


UPD:希望有更多的细节。

-perfasm教授会告诉你一个更完整的故事。或者Windows上的xperfasm教授。真的很有趣。还有谁。。。谢谢你的回答。为什么JMH不减去