Java 为什么我的算法在执行了几次之后会变得更快?(爪哇)

Java 为什么我的算法在执行了几次之后会变得更快?(爪哇),java,performance,algorithm,jvm,jit,Java,Performance,Algorithm,Jvm,Jit,我有一个数独解题算法,我的目标是尽可能快。为了测试这个算法,我多次运行它并计算平均值。在注意到一些奇怪的数字后,我决定一直打印,结果如下: Execution Time : 4.257746 ms (#1) Execution Time : 7.610686 ms (#2) Execution Time : 6.277609 ms (#3) Execution Time : 7.595707 ms (#4) Execution Time : 7.610131 ms (#5) Execution

我有一个数独解题算法,我的目标是尽可能快。为了测试这个算法,我多次运行它并计算平均值。在注意到一些奇怪的数字后,我决定一直打印,结果如下:

Execution Time : 4.257746 ms (#1)
Execution Time : 7.610686 ms (#2)
Execution Time : 6.277609 ms (#3)
Execution Time : 7.595707 ms (#4)
Execution Time : 7.610131 ms (#5)
Execution Time : 5.011104 ms (#6)
Execution Time : 3.970937 ms (#7)
Execution Time : 3.923783 ms (#8)
Execution Time : 4.070238 ms (#9)
Execution Time : 4.765347 ms (#10)
Execution Time : 0.818264 ms (#11)
Execution Time : 0.620216 ms (#12)
Execution Time : 0.679021 ms (#13)
Execution Time : 0.643516 ms (#14)
Execution Time : 0.718408 ms (#15)
Execution Time : 0.744481 ms (#16)
Execution Time : 0.760569 ms (#17)
Execution Time : 0.80384 ms (#18)
Execution Time : 0.75946 ms (#19)
Execution Time : 0.802176 ms (#20)
Execution Time : 66.032508 ms : average = 3.3016254000000003
在执行10到15次(随机变化)后,算法的性能将显著提高。如果我运行它几百次,它最终会稳定在0.3ms左右。请注意,我在这个循环之前运行了一次算法,以便JIT完成它的任务

此外,如果在运行循环之前让线程休眠2秒,则所有时间都是1ms(+/-0.2)

此外,如果我在循环之前解一个普通数独(一个对角线为1-9的网格)大约500次,我所有的时间都在0.3ms(+/-0.02)左右

每个解都是相同的。所有值都将重置

所以我的问题是多方面的:

-为什么连续解算后每次解算时间都会提高


-为什么在10-15次解算后解算时间突然减少?

最有可能的情况是,JVM在多次运行后优化了其执行

除此之外,应用程序本身还可以做一些改进执行结果的事情

如果不知道您运行的详细信息,就很难说得更准确

您是否使用外部资源—数据库连接、JMS队列/主题等。。? 你使用缓存吗


重要的是…

这是因为JVM对该方法进行了一定数量的频繁调用之后,正在编译该方法。实际上,方法不是在第一次调用时编译的。对于每个方法,JVM都维护一个调用计数,每次调用该方法时,该计数都会增加。JVM解释方法,直到其调用计数超过JIT编译阈值。当调用计数达到阈值时,
JIT
编译并优化
字节码
,以便下次被
JVM
调用时运行得更快。因此,在您的例子中,每执行10到15次(随机)后,算法的性能就会显著提高。

我添加了更多的注释。我只使用纯java和简单java。没有队列,没有缓存,没有线程,没有数据库。应用程序在每次循环执行之间完全重置其数据。这就是我所说的——如果不确切知道您做了什么,很难说。如果您没有使用外部资源和缓存,那么是JIT改进了执行结果。JIT不必在第一次运行时进行优化。事实上,它很可能不会,因为优化代码的成本无法很好地证明,除非它是一段重要的代码(运行频率足够高)。您无意中创建了一个解决数独问题的人工生命形式,它可能会演变成天网。现在退出并开始销售椰子。使用
-XX:+printcomilation
java选项检查JIT编译。有一个JVM启动选项可以实时显示关于(去)优化的JIT决策:在这个规模上,这可能是由于其他程序使用了多少
cpu
造成的。应用程序本身可能有一些改进。例如缓存。在第一次运行时,一些数据可能是从外部存储轮询的,但在随后的调用中,相同的数据可能是从缓存中获取的。是的,JIT是独立完成的—级别相对较低。但我说的是纯业务缓存。例如,您的应用程序加载公司(它们很少更改),因此使用缓存可以显著缩短处理时间。“没有JIT能帮你做到这一点。@我对此表示怀疑,因为OP可能是自己写的代码。它是一个数独解算器,我不认为缓存有多大用处。@AlexKreutznaer:是的,你是对的。一般来说,应用程序本身的缓存会提高应用程序的性能。。因为在这种情况下,每次应用程序需要创建一个对象时,JVM都可以节省下来。虽然现代JVM创建一个对象所消耗的资源和时间现在几乎可以忽略不计,但对于大型对象来说,它仍然很重要。@VishalK我开发了许多业务应用程序。问题不是对象创建,问题通常是您花费在获取外部资源和从中获取数据上的时间。这就是适当的缓存可以显著帮助的地方。