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

2022-08-31 23:39:10

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

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

JVM 是 Sun 1.6.0 更新 4。

克服这个问题的想法:

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

注意:显然,对于此解决方案,我正在查看所有因素,包括芯片架构,磁盘类型和配置以及操作系统设置。但是,对于这个问题,我想把重点放在可以做些什么来优化Java应用程序并最大限度地减少“预热”时间。


答案 1

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

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

做到这一点的简单方法是发送虚假消息。您应该确保虚假消息将触发对类的所有访问。例如,如果您发送了一条空消息,但您的progrom将检查该消息是否为空并避免执行某些操作,则此操作将不起作用。

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

(2):实时优化:在运行时,Java VM 会优化部分代码。这是有热身时间的主要原因。

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

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

希望这有帮助。


答案 2

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

尝试-XX:CompileThreshold=1

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

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

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

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

[编辑2]为了回答kittylyst提出的问题:确实,这将用只使用一次的方法快速填充您的代码缓存。它甚至可能使您的整个应用程序变慢。

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

这里的主要问题是代码仍然是“及时”编译的。只要您无法运行至少一次所需的每种方法,该应用程序就会在每次遇到以前从未编译过的内容时“打嗝”几毫秒。

但是,如果你有RAM,你的应用程序很小,或者你可以增加代码缓存的大小,你不介意缓慢的启动时间,你可以试一试。通常,默认设置非常好。


推荐