我有一个方法,第一次执行需要很长时间。但经过几次调用后,时间缩短了大约30倍。因此,为了使我的应用程序更快地响应用户交互,我使用一些关于应用程序初始化的示例数据“预热”此方法(5次)。但这会增加应用启动时间。
我读过,JVM可以优化并编译我的java代码到本机,从而加快速度。
我想知道 - 也许有一些方法可以明确告诉JVM我希望在启动应用程序时编译这个方法吗?
答案 0 :(得分:6)
JVM在运行时进行JiT(及时)优化。这意味着它可以分析代码的执行方式,并进行优化以提高运行时性能。这发生在运行时。如果你看到这个方法在几次执行后变得更快,那可能是因为JiT优化(除非你的分析有缺陷,比方说,因为数据变得更简单,方法变得更快)。如果您的分析是正确的,那么编译为native可能会对您造成伤害,因为您将不再获得运行时优化。
我们可以看到这个方法吗?您可以在不必担心JVM如何工作的情况下加快速度。您应该将完全与最昂贵的操作隔离开来。您还应该验证这不是某种垃圾收集问题。也许方法很好,但有一个GC正在咀嚼时间,当它完成时你的方法以可接受的速度运行。
答案 1 :(得分:3)
JIT优化工作非常精确,因为它们优化了代码实际所做的事情,而不是在不同实例中所做的事情。
由于输入数据不同,甚至可能在不同的运行中JITted代码不同。甚至当环境发生变化时,它可以不止一次地重新优化。
换句话说:如果没有真正的数据,JVM将无法很好地优化代码。 (即它只能做'静态'优化)
但最后,如果你获得如此高的进步(30倍是很多!),很可能它是
修改强>
查看代码后,在Literas.prepareLiteras()
的大循环中,您不断用不同的点调用path.contains(p)
,但路径相同。 SimplePath.contains()
每次调用时都会创建一个边界形状,因此您最终会一次又一次地创建相同的形状。这是应该从内循环中拉出来的一个主要例子。
我不认为JIT可以优化整个方法,但在某些极端情况下,它可能会将getShape()
转换为专用于单个路径的东西,并再次为下一个路径重新编译。不是很好地使用JVM智能,嗯?
答案 2 :(得分:3)
答案 3 :(得分:2)
如果使用Sun JVM,则JIT编译有不同的阈值,具体取决于您使用的是客户端还是服务器JVM。对于客户端,它是对方法的1500次调用,对于服务器,它是10000.您可以使用JVM参数-XX:CompileThreshold=100
将其更改为非常低的值。
这样低的门槛不会有利于您的全球表现。我只建议使用它,以测试热身的性能改善是否受到JIT的影响。
我从未见过热身因素30的改善,这是由JIT优化引起的。然而。这总是由于一些缓存。
答案 4 :(得分:2)
如果您有64位操作系统,可以尝试在64位JVM上运行它。
Oracle的实现中有两个版本的JVM:客户端VM和服务器VM。在32位Windows上,客户端VM是默认值。在64位Windows上,服务器VM是默认设置。
客户端和服务器VM之间的区别在于它们的调整方式:服务器VM比客户端VM执行更积极的优化(并且更早地进行优化)。服务器VM已针对长时间运行的进程优化了设置。客户端VM具有针对桌面使用进行了优化的默认设置:它预先进行的优化较少,但启动速度更快。
我在计算密集型课程中遇到了很大的速度差异;与32位JVM相比,这些有时在64位JVM上的运行速度是原来的两倍。
答案 5 :(得分:1)
大多数情况下我都是hvgotcodes,但问题也可能不是JVM优化,但是在前几次运行来自磁盘的数据后,现在是在缓存中,或者前几次仍在加载并初始化类,但之后它们都在内存中。