jjzjj

java - 从 jdk1.7.0_25 迁移到 jdk1.7.0_40 时的性能回归

coder 2023-08-28 原文

我正在将 Spring 3.1.2 批处理应用程序从 jdk1.7.0_25 迁移到 jdk1.7.0_40 x64 和 Oracle。

使用 Sun 的 OperatingSystemMXBean.getProcessCpuTime() 作为性能指标,结果显示性能降低了 2.5 倍(即,我在 u25 上运行的应用程序要快得多)。

  • 据我所知,这不是由于 java.util.HashMapjava.util.ArrayList changes因为在使用 u25 的 HashMap 和 ArrayList 类引导 u40 时结果是相同的,而且这些变化对于这种差异来说太小了。
  • 这也与 HashMap 并发性无关 regression因为应用程序是单线程的,并且回归在 u40 中被修复..
  • Hotswap 优化似乎也不是问题,因为使用 -Xbatch-Xcomp 运行会产生相同的结果(假设它们之间的服务器编译相同JDK)。
  • 有表演regression关于 java.lang.invoke.MethodHandles 但这似乎无关。除非 Spring 3.1.2 使用它们——我找不到证据。
  • javac 编译似乎也没有变化。

一些一般说明:

  • 每个 JDK 7 版本 >= u40(以及最新的 JDK 8 jdk1.8.0)都会出现此问题,而版本 < u40="" 似乎还不错(包括jdk="" 6="">
  • 普通的旧 Java 代码(例如,运行 1000*1000*1000*some_calc)没有有这个性能问题,这意味着我的代码或使用的库以某种方式做了一些奇怪和意外的事情?
  • 测试是使用相同的数据库实例 (MSSQL 2008 R2) 完成的,这无关紧要。
  • 即使 OperatingSystemMXBean 不可靠,测试的挂起时间也同样不同。
  • 在这两种情况下,GC 似乎同时启动并持续相同的持续时间(我一直在使用 +UseSerialGC 进行测试)。
  • 分析显示没有异常的新热点,尽管它通常显示应用程序范围内的执行时间增加。
  • 测试这些 Sun JDK 或 OpenJDK 版本的 x86 版本(我使用了 these )不会改变结果。
  • 所有测试的代码(在 JDK 6 上运行时除外)都是使用 jdk1.7.0_40 编译的。
  • 已在两台不同的计算机上测试了相同的场景:x64 和 x86。

有什么建议或想法吗?

编辑添加:应用程序的结构是一个运行金融蒙特卡洛模拟的外循环:即大量日期、计算等。因此,它目前有点复杂,我同意,不适合寻找问题。我将不得不尝试缩小它。

最佳答案

看起来问题是由于在 JDK-7133857 中完成的工作造成的,其中 java.lang.Math.pow()java.lang.Math.exp() 是使用 x87 进行内化和计算的。

这些方法在分析应用程序中被广泛使用(!),因此它们的影响相当大。

JDK-8029302 描述并修复了 power of 2 inputs 的问题;并且使用 jdk1.8.0_25 对应用程序进行的测试(问题已解决)显示性能有所提高,但在完成内部化之前没有回到更高级别的 jdk1.7.0_25

以下是我的 JMH 基准测试及其在三个相关 JDK 版本上的 Math.pow() 结果:

package org.sample;

import org.openjdk.jmh.annotations.*;
import java.lang.*;

public class MyBenchmark {

    @State(Scope.Benchmark)
    public static class ThreadState {
        volatile double x = 0;
        volatile double y = 0;
    }

    @Benchmark
    @BenchmarkMode(Mode.Throughput)
    public double powx(ThreadState state) {
        state.x++;
        state.y += 0.5;
        return Math.pow(state.x, state.y);
    }

    @Benchmark
    @BenchmarkMode(Mode.Throughput)
    public double pow3(ThreadState state) {
        state.x++;
        return Math.pow(state.x, 3);
    }

    @Benchmark
    @BenchmarkMode(Mode.Throughput)
    public double pow2(ThreadState state) {
        state.x++;
        return Math.pow(state.x, 2);
    }
}

结果:

英特尔(R) 酷睿(TM) i5-2520M CPU @ 2.50GHz

jdk1.7.0_25 - 内化前

# VM invoker: x:\@sdks\jdks\jdk1.7.0_25\jre\bin\java.exe
...
Result: 4877658.355 (99.9%) 330460.323 ops/s [Average]
  Statistics: (min, avg, max) = (1216417.493, 4877658.355, 6421780.276), stdev = 1399189.700
  Confidence interval (99.9%): [4547198.032, 5208118.678]


# Run complete. Total time: 00:24:48

Benchmark                Mode  Samples         Score  Score error  Units
o.s.MyBenchmark.pow2    thrpt      200  40160618.138  1561135.596  ops/s
o.s.MyBenchmark.pow3    thrpt      200   3678800.153    88678.269  ops/s
o.s.MyBenchmark.powx    thrpt      200   4877658.355   330460.323  ops/s

jdk1.7.0_40 - 内化

# VM invoker: x:\@sdks\jdks\jdk1.7.0_40\jre\bin\java.exe
...
Result: 1860849.245 (99.9%) 94303.387 ops/s [Average]
  Statistics: (min, avg, max) = (418909.582, 1860849.245, 2379936.035), stdev = 399286.444
  Confidence interval (99.9%): [1766545.859, 1955152.632]


# Run complete. Total time: 00:24:48

Benchmark                Mode  Samples        Score  Score error  Units
o.s.MyBenchmark.pow2    thrpt      200  9619333.987   230749.333  ops/s
o.s.MyBenchmark.pow3    thrpt      200  9240043.369   238456.949  ops/s
o.s.MyBenchmark.powx    thrpt      200  1860849.245    94303.387  ops/s

jdk1.8.0_25 - 固定内化

# VM invoker: x:\@sdks\jdks\jdk1.8.0_25\jre\bin\java.exe
...
Result: 1898015.057 (99.9%) 92555.236 ops/s [Average]
  Statistics: (min, avg, max) = (649562.297, 1898015.057, 2359474.902), stdev = 391884.665
  Confidence interval (99.9%): [1805459.821, 1990570.293]


# Run complete. Total time: 00:24:37

Benchmark                Mode  Samples         Score  Score error  Units
o.s.MyBenchmark.pow2    thrpt      200  81840274.815  1979190.065  ops/s
o.s.MyBenchmark.pow3    thrpt      200   9441518.686   206612.404  ops/s
o.s.MyBenchmark.powx    thrpt      200   1898015.057    92555.236  ops/s

如果我没看错的话,2 的幂问题肯定在 JDK-8029302 中得到修复,>2 整数的幂(我刚刚测试了 Math.pow(x, 3))性能在 jdk1.7.0_40 中得到了改进。至于上面在 Math.pow()s 基准测试中所做的奇怪的非整数 powx(),从 jdk1.7.0_25 移动到 jdk1.7.0_40 时,似乎仍有相当大的性能下降(> 3x)。

Math.pow() 中各自的方法替换 Math.exp()org.apache.commons.math3.util.FastMath 完全解决了性能提升的问题 - 就我而言,这是正确的解决方案。

注意:如果有一种简单的方法(即不需要构建 JDK)来设置 -XX:-InlineIntrinsics 标志,这会稍微简单一些。

关于java - 从 jdk1.7.0_25 迁移到 jdk1.7.0_40 时的性能回归,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27037863/

有关java - 从 jdk1.7.0_25 迁移到 jdk1.7.0_40 时的性能回归的更多相关文章

  1. java - 等价于 Java 中的 Ruby Hash - 2

    我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/

  2. java - 从 JRuby 调用 Java 类的问题 - 2

    我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www

  3. java - 我的模型类或其他类中应该有逻辑吗 - 2

    我只想对我一直在思考的这个问题有其他意见,例如我有classuser_controller和classuserclassUserattr_accessor:name,:usernameendclassUserController//dosomethingaboutanythingaboutusersend问题是我的User类中是否应该有逻辑user=User.newuser.do_something(user1)oritshouldbeuser_controller=UserController.newuser_controller.do_something(user1,user2)我

  4. java - 什么相当于 ruby​​ 的 rack 或 python 的 Java wsgi? - 2

    什么是ruby​​的rack或python的Java的wsgi?还有一个路由库。 最佳答案 来自Python标准PEP333:Bycontrast,althoughJavahasjustasmanywebapplicationframeworksavailable,Java's"servlet"APImakesitpossibleforapplicationswrittenwithanyJavawebapplicationframeworktoruninanywebserverthatsupportstheservletAPI.ht

  5. Observability:从零开始创建 Java 微服务并监控它 (二) - 2

    这篇文章是继上一篇文章“Observability:从零开始创建Java微服务并监控它(一)”的续篇。在上一篇文章中,我们讲述了如何创建一个Javaweb应用,并使用Filebeat来收集应用所生成的日志。在今天的文章中,我来详述如何收集应用的指标,使用APM来监控应用并监督web服务的在线情况。源码可以在地址 https://github.com/liu-xiao-guo/java_observability 进行下载。摄入指标指标被视为可以随时更改的时间点值。当前请求的数量可以改变任何毫秒。你可能有1000个请求的峰值,然后一切都回到一个请求。这也意味着这些指标可能不准确,你还想提取最小/

  6. 【Java 面试合集】HashMap中为什么引入红黑树,而不是AVL树呢 - 2

    HashMap中为什么引入红黑树,而不是AVL树呢1.概述开始学习这个知识点之前我们需要知道,在JDK1.8以及之前,针对HashMap有什么不同。JDK1.7的时候,HashMap的底层实现是数组+链表JDK1.8的时候,HashMap的底层实现是数组+链表+红黑树我们要思考一个问题,为什么要从链表转为红黑树呢。首先先让我们了解下链表有什么不好???2.链表上述的截图其实就是链表的结构,我们来看下链表的增删改查的时间复杂度增:因为链表不是线性结构,所以每次添加的时候,只需要移动一个节点,所以可以理解为复杂度是N(1)删:算法时间复杂度跟增保持一致查:既然是非线性结构,所以查询某一个节点的时候

  7. 【Java入门】使用Java实现文件夹的遍历 - 2

    遍历文件夹我们通常是使用递归进行操作,这种方式比较简单,也比较容易理解。本文为大家介绍另一种不使用递归的方式,由于没有使用递归,只用到了循环和集合,所以效率更高一些!一、使用递归遍历文件夹整体思路1、使用File封装初始目录,2、打印这个目录3、获取这个目录下所有的子文件和子目录的数组。4、遍历这个数组,取出每个File对象4-1、如果File是否是一个文件,打印4-2、否则就是一个目录,递归调用代码实现publicclassSearchFile{publicstaticvoidmain(String[]args){//初始目录Filedir=newFile("d:/Dev");Datebeg

  8. ruby-on-rails - 如何从过时的 TZInfo 标识符中获取 Rails TimeZone 名称? - 2

    已经有一个问题回答了如何将“America/Los_Angeles”转换为“PacificTime(US&Canada)”。但是我想将“美国/太平洋”和其他过时的时区转换为RailsTimeZone。我无法在图书馆中找到任何可以帮助我完成此任务的东西。 最佳答案 来自RailsActiveSupport::TimeZonedocs:TheversionofTZInfobundledwithActiveSupportonlyincludesthedefinitionsnecessarytosupportthezonesdefinedb

  9. java - 为什么 ruby​​ modulo 与 java/other lang 不同? - 2

    我基本上来自Java背景并且努力理解Ruby中的模运算。(5%3)(-5%3)(5%-3)(-5%-3)Java中的上述操作产生,2个-22个-2但在Ruby中,相同的表达式会产生21个-1-2.Ruby在逻辑上有多擅长这个?模块操作在Ruby中是如何实现的?如果将同一个操作定义为一个web服务,两个服务如何匹配逻辑。 最佳答案 在Java中,模运算的结果与被除数的符号相同。在Ruby中,它与除数的符号相同。remainder()在Ruby中与被除数的符号相同。您可能还想引用modulooperation.

  10. java - Ruby 相当于 Java 的 Collections.unmodifiableList 和 Collections.unmodifiableMap - 2

    Java的Collections.unmodifiableList和Collections.unmodifiableMap在Ruby标准API中是否有等价物? 最佳答案 使用freeze应用程序接口(interface):Preventsfurthermodificationstoobj.ARuntimeErrorwillberaisedifmodificationisattempted.Thereisnowaytounfreezeafrozenobject.SeealsoObject#frozen?.Thismethodretur

随机推荐