相关疑难解决方法(0)

如何在Java中编写正确的微基准测试?

你如何在Java中编写(并运行)正确的微基准测试?

我在这里寻找代码示例和注释,说明要考虑的各种事项.

示例:基准测量应该测量时间/迭代或迭代/时间,为什么?

相关:秒表基准可以接受吗?

java benchmarking jvm jvm-hotspot microbenchmark

835
推荐指数
11
解决办法
11万
查看次数

为什么Java没有真正的多维数组?

TL; DR版本,对于那些不想要背景的人,是以下具体问题:

为什么Java没有真正的多维数组的实现?有坚实的技术原因吗?我在这里错过了什么?

背景

Java在语法级别具有多维数组,可以声明

int[][] arr = new int[10][10];
Run Code Online (Sandbox Code Playgroud)

但似乎这真的不是人们所期望的.它不是让JVM分配足够大的连续RAM块来存储100 int秒,而是作为ints 的数组阵列出现:所以每个层都是一个连续的RAM块,但整体而言并非如此.arr[i][j]因此访问速度相当慢:JVM必须这样做

  1. 找到int[]存储的arr[i];
  2. 索引这个找到int存储的arr[i][j].

这涉及查询对象从一层到另一层,这是相当昂贵的.

为什么Java会这样做

在一个层面上,不难看出为什么这不能被优化为简单的扩展和添加查找,即使它们都被分配在一个固定块中.问题是arr[3]它本身就是一个引用,它可以被改变.因此,尽管数组具有固定大小,但我们可以轻松编写

arr[3] = new int[11];
Run Code Online (Sandbox Code Playgroud)

现在,由于这一层已经成长,因此缩放和加载是固定的.您需要在运行时知道是否所有内容仍然与以前相同.此外,当然,这将被分配到RAM中的其他地方(它必须是,因为它比它更换的更大),所以它甚至不适合扩展和添加.

这有什么问题

在我看来,这并不理想,这有两个原因.

首先,它很.我使用这些方法运行的测试用于求和单维或多维数组的内容,对于多维情况(a 和a 分别填充随机值,运行1000000次,温度)几乎是两倍长(714秒对371秒)高速缓存).int[1000000]int[100][100][100]int

public static long sumSingle(int[] arr) {
    long total = 0;
    for (int i=0; i<arr.length; i++)
        total+=arr[i];
    return total;
}

public static long sumMulti(int[][][] arr) {
    long total = 0; …
Run Code Online (Sandbox Code Playgroud)

java arrays performance multidimensional-array

35
推荐指数
4
解决办法
6726
查看次数

是否有一种轻量级方法可以在 Java 9+ 中添加安全点

Java 9+ 中是否有更便宜的方法调用来保持其安全点?

JVM 在运行时移除安全点以提高效率,但这会使分析和监控代码变得更加困难。出于这个原因,我们特意在精心挑选的地方添加了琐碎的调用,以确保存在安全点。

public static void safepoint() {
    if (IS_JAVA_9_PLUS)
        Thread.holdsLock(""); // 100 ns on Java 11
    else
        Compiler.enable(); // 5 ns on Java 8
}

public static void optionalSafepoint() {
    if (SAFEPOINT_ENABLED)
        if (IS_JAVA_9_PLUS)
            Thread.holdsLock("");
        else
            Compiler.enable();
}
Run Code Online (Sandbox Code Playgroud)

在 Java 8 上,这种开销很好,但Compiler.enable()在 Java 9+ 中被优化掉了,所以我们必须使用更昂贵的方法,或者不启用此功能。

编辑:除了分析器之外,我还使用了safepoint()从中获取更好的细节,Thread.getStackTrace()以便应用程序可以对其自身进行分析,例如,当执行操作需要很长时间时。

java jvm java-11

18
推荐指数
1
解决办法
517
查看次数

当JVM无法达到安全点时如何获取Java堆栈

我们最近有一种情况,我们的一个生产JVM会随机冻结.Java进程正在烧毁CPU,但所有可见活动都将停止:没有日志输出,没有写入GC日志,没有响应任何网络请求等.进程将保持此状态直到重新启动.

原来,该org.mozilla.javascript.DToA类,某些输入调用时,会感到困惑,并呼吁BigInteger.pow着巨大的值(例如5 ^ 2147483647),这会触发JVM冻结.我的猜测是,一些大循环,可能是在java.math.BigInteger.multiplyToLen中,在循环中没有安全点检查的情况下进行了JIT.下次JVM需要暂停进行垃圾收集时,它会冻结,因为运行BigInteger代码的线程很长时间都不会达到安全点.

我的问题:将来,我如何诊断这样的安全点问题?杀-3没有产生任何输出; 我认为它依赖于安全点来生成准确的堆栈.是否有任何生产安全的工具可以从正在运行的JVM中提取堆栈而无需等待安全点?(在这种情况下,我真的很幸运,并设法抓住一组堆叠的痕迹BigInteger.pow被调用刚过,但在此之前它的工作它的方式到足够大的输入完全楔入JVM,没有运气中风,我我不确定我们怎么会诊断出这个问题.)

编辑:以下代码说明了问题.

// Spawn a background thread to compute an enormous number.
new Thread(){ @Override public void run() {
  try {
    Thread.sleep(5000);
  } catch (InterruptedException ex) {
  }
  BigInteger.valueOf(5).pow(100000000);
}}.start();

// Loop, allocating memory and periodically logging progress, so illustrate GC pause times.
byte[] b;
for (int outer = 0; ; outer++) {
  long startMs = System.currentTimeMillis();
  for (int inner = 0; inner < 100000; inner++) {
    b = new byte[1000];
  }

  System.out.println("Iteration " …
Run Code Online (Sandbox Code Playgroud)

jit garbage-collection jvm freeze stack-trace

15
推荐指数
2
解决办法
2276
查看次数

为什么IntStream.average()总是返回正确的结果,而LongStream.average()有时不会?

double average = LongStream
   .of(-4480186093928204294L, -1340542863544260591L, -6004296286240039273L)
   .average()
   .getAsDouble()
Run Code Online (Sandbox Code Playgroud)

这会返回,2.20723960999901594E18但我希望它会返回-3.9416750812375014E18.

另一方面,这会返回正确的结果(-1.4628605853333333E9):

double average = IntStream
   .of(-1282256274, -1645263673, -1461061809)
   .average()
   .getAsDouble()
Run Code Online (Sandbox Code Playgroud)

为什么IntStream.average()总是返回正确的平均值,LongStream.average()有时却没有?

java java-8 java-stream

2
推荐指数
1
解决办法
198
查看次数