- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
我试图重现 here 中描述的一些处理器缓存效果。 .我知道 Java 是一个托管环境,这些示例无法准确翻译,但我遇到了一个奇怪的案例,我试图提炼出一个简单的示例来说明效果:
public static void main(String[] args) {
final int runs = 10;
final int steps = 1024 * 1024 * 1024;
for (int run = 0; run < runs; run++) {
final int[] a = new int[1];
long start = System.nanoTime();
for (int i = 0; i < steps; i++) {
a[0]++;
}
long stop = System.nanoTime();
long time = TimeUnit.MILLISECONDS.convert(stop - start, TimeUnit.NANOSECONDS);
System.out.printf("Time for loop# %2d: %5d ms\n", run, time);
}
}
输出:
Time for loop# 0: 24 ms
Time for loop# 1: 106 ms
Time for loop# 2: 104 ms
Time for loop# 3: 103 ms
Time for loop# 4: 102 ms
Time for loop# 5: 103 ms
Time for loop# 6: 104 ms
Time for loop# 7: 102 ms
Time for loop# 8: 105 ms
Time for loop# 9: 102 ms
内部循环的第一次迭代大约是后续迭代的 4 倍。这与我通常期望的相反,因为通常性能会随着 JIT 的启动而上升。
当然,在任何严重的微基准测试中都会做几个热身循环,但我很好奇是什么导致了这种行为,特别是因为如果我们知道循环可以在 24 毫秒内执行,它不是非常满意,稳态时间超过100ms。
供引用我正在使用的JDK(在linux上):
openjdk version "1.8.0_40"
OpenJDK Runtime Environment (build 1.8.0_40-b20)
OpenJDK 64-Bit Server VM (build 25.40-b23, mixed mode)
更新:
以下是一些更新信息,基于一些评论和一些实验:
1) 将 System.out I/O 移出循环(通过将时间存储在大小为“运行”的数组中)在时间上没有显着差异。
2) 上面显示的输出是当我在 Eclipse 中运行时。当我从命令行(使用相同的 JDK/JVM)编译和运行时,我得到的结果更温和,但仍然很重要(快 2 倍而不是 4 倍)。这看起来很有趣,因为通常在 eclipse 中运行会减慢速度。
3) 将 a
向上移动,移出循环,这样每次迭代都可以重用它。
4) 如果将 int[] a
改为 long[] a
,第一次迭代运行得更快(大约 20%),而其他迭代仍然相同(较慢)的速度。
更新 2:
我认为 apangin 的回答解释了这一点。我在 Sun 的 1.9 JVM 上试过这个,它来自:
openjdk version "1.8.0_40"
OpenJDK Runtime Environment (build 1.8.0_40-b20)
OpenJDK 64-Bit Server VM (build 25.40-b23, mixed mode)
Time for loop# 0: 48 ms
Time for loop# 1: 116 ms
Time for loop# 2: 112 ms
Time for loop# 3: 113 ms
Time for loop# 4: 112 ms
Time for loop# 5: 112 ms
Time for loop# 6: 111 ms
Time for loop# 7: 111 ms
Time for loop# 8: 113 ms
Time for loop# 9: 113 ms
到:
java version "1.9.0-ea"
Java(TM) SE Runtime Environment (build 1.9.0-ea-b73)
Java HotSpot(TM) 64-Bit Server VM (build 1.9.0-ea-b73, mixed mode)
Time for loop# 0: 48 ms
Time for loop# 1: 26 ms
Time for loop# 2: 22 ms
Time for loop# 3: 22 ms
Time for loop# 4: 22 ms
Time for loop# 5: 22 ms
Time for loop# 6: 22 ms
Time for loop# 7: 22 ms
Time for loop# 8: 22 ms
Time for loop# 9: 23 ms
这是相当的进步!
最佳答案
这是对方法的次优重新编译。
JIT 编译器依赖于在解释期间收集的运行时统计信息。当 main
方法第一次编译时,外循环还没有完成它的第一次迭代 => 运行时统计告诉内循环之后的代码永远不会执行,所以 JIT 不会不必费心编译它。它反而会产生一个不常见的陷阱。
当内部循环第一次结束时,不常见的陷阱被命中,导致方法被去优化。
在外循环的第二次迭代中,main
方法将使用新知识重新编译。现在 JIT 有更多的统计数据和更多的上下文来编译。由于某种原因,现在它没有在寄存器中缓存值 a[0]
(可能是因为 JIT 被更广泛的上下文所欺骗)。所以它生成addl
指令来更新内存中的数组,这实际上是内存加载和存储的组合。
相反,在第一次编译时,JIT 将 a[0]
的值缓存在寄存器中,只有 mov
指令将值存储在内存中(无负载)。
快速循环(第一次迭代):
0x00000000029fc562: mov %ecx,0x10(%r14) <<< array store
0x00000000029fc566: mov %r11d,%edi
0x00000000029fc569: mov %r9d,%ecx
0x00000000029fc56c: add %edi,%ecx
0x00000000029fc56e: mov %ecx,%r11d
0x00000000029fc571: add $0x10,%r11d <<< increment in register
0x00000000029fc575: mov %r11d,0x10(%r14) <<< array store
0x00000000029fc579: add $0x11,%ecx
0x00000000029fc57c: mov %edi,%r11d
0x00000000029fc57f: add $0x10,%r11d
0x00000000029fc583: cmp $0x3ffffff2,%r11d
0x00000000029fc58a: jl 0x00000000029fc562
慢循环(重新编译后):
0x00000000029fa1b0: addl $0x10,0x10(%r14) <<< increment in memory
0x00000000029fa1b5: add $0x10,%r13d
0x00000000029fa1b9: cmp $0x3ffffff1,%r13d
0x00000000029fa1c0: jl 0x00000000029fa1b0
不过,这个问题似乎在 JDK 9 中得到了解决。我已经对照最近的 JDK 9 Early Access 版本检查了这个测试,并验证它可以按预期工作:
Time for loop# 0: 104 ms
Time for loop# 1: 101 ms
Time for loop# 2: 91 ms
Time for loop# 3: 63 ms
Time for loop# 4: 60 ms
Time for loop# 5: 60 ms
Time for loop# 6: 59 ms
Time for loop# 7: 55 ms
Time for loop# 8: 57 ms
Time for loop# 9: 59 ms
关于java - 为什么这个内部循环第一次迭代通过外部循环快 4 倍?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31527387/
如何指示 webpack 排除所有 d3 模块? // does not work externals: { "d3-*": "d3" } 所以如果应用导入了d3-submod
这个问题在这里已经有了答案: 9年前关闭。 Possible Duplicate: What does “outer =>” really mean? 我在哪里可以找到有关信息 trait After
这是一个简单的循环,我正在尝试对性能进行基准测试。 var extremeLoop=function(n){ var time=new Date() var t=0; for(
问题+概述 下面是两个片段,其中包含最初隐藏的 div,然后通过单击 button 和 jQuery 的 .show() 显示。两个 div 都具有由外部样式表应用的 display: grid; 样
我有一个 HTML 页面和一个单独的 .js 文件,该文件包含在带有 的页面中标签。 这是我的 .js 文件: element = document.getElementById("test");
我在 linux 静态库项目中有 3 个文件,我想在两个类方法实现文件中使用的静态字段存在链接问题。我有 class1.h、class1main.cpp 和 class1utils.cpp。 clas
我正在尝试将颜色背景更改为默认背景颜色,当我点击输入框外 我尝试使用“null”或“none”但没有用? window.addEventListener('click', outsideClick);
我正在编写一个应用程序,要求用户在手机上选择各种类型的文件。我使用此代码启动文件选择器 Intent : Intent intent = new Intent(Intent.ACTION_GET_C
在 android 中,不可移动(内部)的外部存储和内部存储有什么区别?我不确定在哪里保存我的数据。我只需要保存一个人可以随时提取的游戏统计数据 谢谢 最佳答案 在许多较新的设备中,将不再有物理区别,
在 C++ 中,假设我们有这个头文件: myglobals.h #ifndef my_globals_h #define my_globals_h int monthsInYear = 12; #en
我正在尝试使用 externs 在 C++ 中连接到 Ada。这两种实现有什么区别? 实现A namespace Ada { extern "C" { int getN
这个问题在这里已经有了答案: Get selected element's outer HTML (30 个答案) 关闭 2 年前。 想象一下我们有这样的东西: Hello World 如果我们这样
假设我在模块的顶部有这个: Public Declare Function getCustomerDetails Lib "CustomerFunctions" () As Long 如果我从 VB6
我目前正在使用这段代码: var wordRandomizer = { run: function (targetElem) { var markup = this.creat
我们正在使用 SVN 试水,并以 Beanstalk 作为主机。我们的设置如下所示: 存储库:模块 模块一 模块二 模块 3 存储库:网站1 自定义网站代码 svn:对模块 1 的外部引用 svn:对
有没有办法在负载均衡器中设置自动外部 IP 分配给像谷歌这样的服务? 我在裸机上运行 Kubernetes。 谢谢 最佳答案 使用 nodePort 类型的服务,它会将您的服务绑定(bind)到所有节
是否有可能在 Controller 之外使用 generateUrl() 方法? 我尝试在带有 $this->get('router') 的自定义存储库类中使用它,但它没有用。 更新 我在这里找到了一
我目前正在尝试通过 Webpack 外部对象外部化 Angular 依赖项来缩短构建时间。到目前为止,我已经为 React 和其他小库实现了这一目标。 如果我只是移动 '@angular/compil
我想创建一个自动应用其他插件的插件(外部插件)。这要求在我称为“应用插件”之前为插件设置构建脚本依赖项。但是似乎我无法在插件中添加buildscript依赖项,或者得到了: 您不能更改处于未解析状态的
我是R包的创建者EnvStats . 有一个我经常使用的函数,叫做 stripChart .我刚开始学习ggplot2 ,并在过去几天里仔细研究了 Hadley 的书、Winston 的书、Stack
我是一名优秀的程序员,十分优秀!