如何预热Java类以避免缓慢的首次调用?


13

我正在做一个项目,我需要所有API调用花费少于1秒的时间,但是我遇到的问题是第一次调用每条路由的速度都慢于随后的路由。

目前,首次拨打/ login的时间为3.6秒,接下来的通话为170毫秒,其他所有路由都相同。

我发现-XX:+TraceClassLoading在第一次调用时使用了该类,这些类已加载到内存中,这导致了性能问题。

但是,我没有找到一种在启动时加载所有类的简便方法,对于每个新服务,我需要在ApplicationRunner中添加一个热身调用。

是否有人可以自动加载SpringBoot应用程序的类或预热其所有路由的解决方案?


您可以添加更多详细信息吗?您的应用程序实例化了控制程序吗?还是您正在致电其他服务?您如何拨打其他服务的电话?
Menios

Spring Boot大量使用类扫描,因此您不需要像台式机应用程序那样“热身”。如此长的初始加载可能是资源搜索的结果-例如页面模板加载。
Alex Chernyshev

有点间接的方法:如果您对端点拥有100%的单元测试覆盖率,则可以使用它们。你仍然必须每个端点代码,但你获得的东西
Marged

1
根据您正在执行的项目,可能并不理想,但是可以在加载应用程序时在内部调用端点。
omoshiroiii

@omoshiroiii 问题。我们做到了。在生产中。原因与使用的某些动态库有关invokedynamic,我们知道对这些函数的第一次调用的分辨率很慢(我们有成千上万个这样的调用,没有这个第一次调用,它们的累积时间为数十秒)。
尤金

Answers:


1

Java的类加载是延迟的。这意味着仅当需要时,JVM才加载类。

如果要强制它急于加载类,则只需引用它们即可。一种方法是遍历jar内容或类文件以获得类名,然后使用它们进行调用Class.forName(className)

此外,如果启动时间和性能对于您的用例非常重要,则您可能希望提前研究GraalVM之类的编译解决方案,或者降低JIT的编译门槛(-XX:CompileThreshold)。


这些都不能解决OP的问题。在GraalVM中,加载仍然是延迟的,并且JIT在第一次调用时确实没有任何意义。
尤金

GraalVM很好,但是请查看它在github中遇到的问题:一旦您从沙盒项目转到更大的项目(主要是我在考虑您的反思),您就会有些痛苦,至少。我的观点是:切换到GraalVM并非易事。
尤金

我曾考虑过将类加载到jar中,但没有找到一种方法,请问有一个例子吗?
Ybri

@Eugene,如果您阅读我的答案,您会发现我没有说GraalVM或JIT阈值会改变类加载的延迟。OP关于懒惰的问题的答案是在那之前的一段。最后一段只是在OP需要进一步优化启动时间/性能(超出类加载)的其他提示。
andresp

1
@Ybri有与答案的其他问题,在这里,如stackoverflow.com/questions/2370867/...
andresp

0

对我来说,你唯一可行的办法是class data sharing,整个传播JEP 310JEP 341JEP 350,但是这需要Java-13最有可能。我们正在我的工作场所进行内部测试(主要是出于娱乐目的,不要撒谎),到目前为止,结果看起来不错。

另一个选择是在应用程序启动时调用您的端点-如果可以的话。再次,这对我们的例子:我们称之为虚拟数据一对夫妇数百次的热身代码。但是,与此同时,我们在不可能的地方提供服务-这就是为什么CDS也要探索的原因。


您如何处理身份验证和发布端点,以避免在生产数据库中创建数据?
Ybri

@Ybri正是我说的原因,对某些人来说是不可能的。
尤金
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.