最小化Java“预热”的技术或实用程序时间?

发布于 2024-08-05 09:40:32 字数 645 浏览 2 评论 0原文

我正在支持需要低延迟(处理每条消息< 300 微秒)的 Java 消息传递应用程序。然而,我们的分析表明,Sun Java 虚拟机一开始运行缓慢,在前 5,000 条消息后速度加快。前 5,000 条消息的延迟为 1-4 毫秒。在大约前 5,000 条之后,后续消息的延迟约为 250 微秒,偶尔会出现异常值。

人们普遍认为这是 Java 应用程序的典型行为。然而,从业务角度来看,告诉客户他们必须等待 JVM“预热”才能看到他们所需的性能是不可接受的。在处理第一条客户消息之前,需要对应用程序进行“预热”

JVM 是 Sun 1.6.0 update 4。

克服此问题的思路:

  1. JVM 设置,例如 -XX:CompileThreshold=
  2. 在“warm-”中添加一个组件在启动时启动“应用程序”,例如通过应用程序发送“假消息”。
  3. 在应用程序启动时静态加载应用程序和 JDK 类,以便在处理客户消息时不会从 JAR 加载类。
  4. 一些实用程序或 Java 代理可以实现上述两个想法中的一个或两个,这样我就不必重新发明轮子。

注意:显然,对于此解决方案,我正在考虑所有因素,包括芯片架构、磁盘类型和配置以及操作系统设置。然而,对于这个问题,我想重点讨论如何优化 Java 应用程序并最大限度地减少“预热”时间。

I am supporting a Java messaging application that requires low latency (< 300 microseconds processing each message). However, our profiling shows that the Sun Java Virtual Machine runs slowly at first, and speeds up after the first 5,000 messages or so. The first 5,000 messages have latency of 1-4 milliseconds. After about the first 5,000, subsequent messages have ~250 microseconds latency, with occasional outliers.

It's generally understood that this is typical behavior for a Java application. However, from a business standpoint it's not acceptable to tell the customer that they have to wait for the JVM to "warm-up" before they see the performance they demand. The application needs to be "warmed-up" before the first customer message is processed

The JVM is Sun 1.6.0 update 4.

Ideas for overcoming this issue:

  1. JVM settings, such as -XX:CompileThreshold=
  2. Add a component to "warm-up" the application on startup, for example by sending "fake messages" through the application.
  3. Statically load application and JDK classes upon application startup, so that classes aren't loaded from JARs while processing customer messages.
  4. Some utility or Java agent that accomplishes either or both of the above two ideas, so that I don't have to re-invent the wheel.

NOTE: Obviously for this solution I'm looking at all factors, including chip arch, disk type and configuration and OS settings. However, for this question I want to focus on what can be done to optimize the Java application and minimize "warm up" time.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

笑梦风尘 2024-08-12 09:40:32

Java 中的“热身”通常涉及两件事:

(1):延迟类加载:这可以通过强制加载来解决。

最简单的方法就是发送一条虚假消息。您应该确保假消息将触发对类的所有访问。例如,如果您发送一条空消息,但您的程序会检查该消息是否为空并避免执行某些操作,那么这将不起作用。

另一种方法是在程序启动时通过访问该类来强制类初始化。

(2):实时优化:在运行时,Java VM会对代码的某些部分进行优化。这是需要预热时间的主要原因。

为了缓解这个问题,您可以发送一堆假的(但看起来真实的)消息,以便优化可以在用户使用它之前完成。

另一个可以帮助缓解这个问题的方法是支持内联,例如尽可能多地使用 private 和 Final。原因是,VM不需要查找继承表来查看实际调用的方法。

希望这有帮助。

"Warm-up" in Java is generally about two things:

(1): Lazy class loading: This can be work around by force it to load.

The easy way to do that is to send a fake message. You should be sure that the fake message will trigger all access to classes. For exmaple, if you send an empty message but your progrom will check if the message is empty and avoid doing certain things, then this will not work.

Another way to do it is to force class initialization by accessing that class when you program starts.

(2): The realtime optimization: At run time, Java VM will optimize some part of the code. This is the major reason why there is a warm-up time at all.

To ease this, you can sent bunch of fake (but look real) messages so that the optimization can finish before your user use it.

Another that you can help to ease this is to support inline such as using private and final as much as you can. the reason is that, the VM does not need to look up the inheritance table to see what method to actually be called.

Hope this helps.

以往的大感动 2024-08-12 09:40:32

您的问题不是类加载,而是“及时”编译。

尝试 -XX:CompileThreshold=1

这将强制 Java 在第一次运行时编译所有内容。它会稍微减慢代码的启动速度,但不会减慢 VM 代码的速度(因为安装 Java 时会编译 VM 代码)。有一个 bug 允许 Java 以类似的方式编译自定义 JAR 并保存结果以供以后执行,这将大大减少这种开销,但没有压力很快修复这个 bug。

第二种选择是向应用程序发送 5,000 条虚假消息以“预热”。将此推销为“确保一切设置正确”。

[编辑]预编译类中的一些背景信息: 类数据共享

您可能想尝试 IBM 版本的 Java,因为在这里,您可以向共享池添加更多类:类数据共享概述

[EDIT2] 回答 kittylyst 提出的问题:确实,这将很快用仅使用的方法填满您的代码缓存一次。它甚至可能会使您的整个应用程序变慢。

如果将其设置为较低的值,应用程序的启动时间可能会变得非常慢。这是因为 JIT 优化 + 运行编译后的代码比在解释模式下运行一次代码更昂贵。

这里的主要问题是代码仍然是“及时”编译的。只要您不能至少运行一次所需的每个方法,应用程序每次遇到以前未编译过的内容时都会“卡顿”几毫秒。

但是,如果您有 RAM,您的应用程序很小,或者您可以增加代码缓存的大小,并且您不介意启动时间较慢,则可以尝试一下。一般来说,默认设置就很好。

Your problem is not class loading but "just in time" compilation.

Try -XX:CompileThreshold=1

That will force Java to compile everything the first time it runs it. It will slow down the startup of your code somewhat but not VM code (since that gets compiled when Java is installed). There is a bug open to allow Java to compile custom JARs in a similar way and save the result for later executions which would greatly reduce this overhead but there is no pressure to fix this bug any time soon.

A second option would be to send 5'000 fake messages to the app to "warm it up". Sell this as "making sure everything is set up correctly".

[EDIT] Some background info in precompiling classes: Class Data Sharing

You may want to try IBM's version of Java since here, you can add more classes to the shared pool: Overview of class data sharing

[EDIT2] To answer concerns raised by kittylyst: It's true that this will quickly fill up your code cache with methods that are used only once. And it might even make your whole app slower.

If you set it to a low value, the startup time of your application can become horribly slow. This is because the JIT optimization + running the compiled code is more expensive than running the code once in interpreted mode.

The main problem here is that the code is still compiled "just in time". As long as you can't run every method that you need at least once, the app will "hickup" for a few milliseconds every time it encounters something that hasn't been compiled before.

But if you have the RAM, your app is small or you can increase the size of the code cache and you don't mind the slow startup time, you can give this a try. Generally, the default setting is pretty good.

情域 2024-08-12 09:40:32

只需在系统开放真正的客户流量之前通过系统运行一堆无操作消息即可。 10k 条消息是通常的数字。

对于金融应用程序(例如 FIX),这通常是通过在开盘前向市场发送订单(价格远离昨晚收盘价,以防万一)来完成的。他们都会被拒绝,但这并不重要。

如果您使用的协议是自制协议,那么下次升级它的库时,请添加对“WARMUP”或“TEST”或“SANITYCHECK”消息类型的显式支持。

当然,这可能不会编译您的应用程序逻辑特定路径,但在一个不错的消息应用程序中,处理网络流量的部分几乎肯定是堆栈的主要部分,所以这并不重要。

Just run a bunch of no-op messages through the system before it's opened for genuine customer traffic. 10k messages is the usual number.

For financial apps (e.g. FIX), this is often done by sending orders (at a price far away from last night's close, just in case) to the market before it opens. They'll all get rejected, but that doesn't matter.

If the protocol you're using is homebrew, then the next time you upgrade the libraries for it, add explicit support for a "WARMUP" or "TEST" or "SANITYCHECK" message type.

Of course, this likely won't compile up your application-logic-specific pathways, but in a decent messaging app, the part dealing with network traffic will almost certainly be the dominant part of the stack, so that doesn't matter.

水中月 2024-08-12 09:40:32

您使用的是客户端 JVM 还是服务器 JVM?尝试这样启动你的程序:

java -server com.mycompany.MyProgram

当在这种模式下运行 Sun 的 JVM 时,JIT 会提前将字节码编译为本机代码;因此,程序启动时间会更长,但之后运行速度会更快。

参考:有关 Java HotSpot VM 的常见问题

引用:

客户端系统和服务器系统有什么区别?

这两个系统是不同的二进制文件。它们本质上是连接到同一运行时系统的两个不同的编译器(JIT)。客户端系统最适合需要快速启动时间或较小占用空间的应用程序,服务器系统最适合整体性能最重要的应用程序。一般来说,客户端系统更适合交互式应用程序,例如 GUI。其他一些差异包括编译策略、堆默认值和内联策略。

Are you using the client or the server JVM? Try starting your program with:

java -server com.mycompany.MyProgram

When running Sun's JVM in this mode, the JIT will compile the bytecode to native code earlier; because of this, the program will take longer to start, but it will run faster after that.

Reference: Frequently Asked Questions About the Java HotSpot VM

Quote:

What's the difference between the -client and -server systems?

These two systems are different binaries. They are essentially two different compilers (JITs)interfacing to the same runtime system. The client system is optimal for applications which need fast startup times or small footprints, the server system is optimal for applications where the overall performance is most important. In general the client system is better suited for interactive applications such as GUIs. Some of the other differences include the compilation policy,heap defaults, and inlining policy.

英雄似剑 2024-08-12 09:40:32

如果在现代硬件(每个 CPU 有 2 个或更多核心)和最新版本的 JDK 上以 Hotspot 的服务器模式运行,则可以使用以下选项来加速预热:

-server -XX:+TieredCompilation

If running in Hotspot's server mode on contemporary hardware (with 2 or more cores per CPU) and with latest version of JDK then following option can be used for speeding of warming up:

-server -XX:+TieredCompilation
如梦初醒的夏天 2024-08-12 09:40:32

老线程,我知道,但我在互联网上找到了这个:

一个非常有趣的事情是选项-XX:CompileThreshold=1500对SUN HotSpot JVM的影响。服务器 VM 的默认值为 10000,客户端 VM 的默认值为 1500。但是,将服务器 VM 设置为 1500 会使其比客户端 VM 更快。将其设置为 100 实际上会降低性能。而使用选项-Xcomp(这意味着所有代码在使用之前都经过编译)的性能甚至更低,这令人惊讶。

现在你知道该怎么做了。

Old thread, I know, but I found this in the internet:

A very interesting thing is the influence of option-XX:CompileThreshold=1500 to SUN HotSpot JVM. The default is 10000 for Server VM and 1500 for Client VM. However setting it to 1500 for Server VM makes it faster than Client VM. Setting it to 100 actualy lowers the performance. And using option-Xcomp (which means that all code is compiled before usage) gives even lower performance, which is surprising.

Now you know what to do.

国产ˉ祖宗 2024-08-12 09:40:32

看来您的项目将从实时保证中受益:

请参阅:Real Time Java

Seems like your project would benefit from real time guarantees:

See: Real Time Java

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文