性能文章>【译】JVM c1、c2编译线程CPU消耗高怎么办?>

【译】JVM c1、c2编译线程CPU消耗高怎么办?转载

2年前
529633

c1、c2 编译器线程由 Java 虚拟机创建,以优化您的应用程序的性能。有时这些线程会倾向于消耗高 CPU。在这篇文章中,让我们更多地了解 c1、c2 编译器线程以及如何解决它们的高 CPU 消耗问题。

读完这篇文章后,诸如 Hotspot JIT、c1 编译器线程、c2 编译器线程、代码缓存之类的术语可能不会吓到你(就像过去曾经吓到我一样)。

什么是热点 JIT 编译器?

您的应用程序可能有数百万行代码。然而,只有一小部分代码被一次又一次地执行。这个小代码子集(也称为“热点”)负责您的应用程序性能。在运行时 JVM 使用这个 JIT (Just in time) 编译器来优化这个热点代码。大多数时候,应用程序开发人员编写的代码并不是最优的。因此,JVM 的 JIT 编译器优化了开发人员的代码以获得更好的性能。为了做这种优化,JIT 编译器使用 C1、C2 编译器线程。 

什么是代码缓存? 

JIT 编译器用于此代码编译的内存区域称为“代码缓存”。该区域位于 JVM 堆和元空间之外。要了解不同的 JVM 内存区域,可以点击

c1 和 c2 编译器线程有什么区别?

 在 Java 的早期,有两种类型的 JIT 编译器:

1,客户端

2,服务器

根据您要使用的 JIT 编译器类型,必须下载和安装适当的 JDK。假设您正在构建桌面应用程序,则需要下载具有“客户端”JIT 编译器的 JDK。如果您正在构建服务器应用程序,则需要下载具有“服务器”JIT 编译器的 JDK。

客户端 JIT 编译器在应用程序启动后立即开始编译代码。服务器 JIT 编译器将观察代码执行相当长的一段时间。根据它获得的执行知识,它将开始进行 JIT 编译。尽管服务器 JIT 编译速度很慢,但它生成的代码将比客户端 JIT 编译器生成的代码更加优越和高效。

今天,现代 JDK 附带了客户端和服务器 JIT 编译器。两个编译器都试图优化应用程序代码。在应用程序启动期间,使用客户端 JIT 编译器编译代码。后来随着知识的增加,使用服务器 JIT 编译器编译代码。这在 JVM 中称为分层编译。 

 JDK 开发人员将它们称为客户端和服务器 JIT 编译器,内部称为 c1 和 c2 编译器。因此,客户端 JIT 编译器使用的线程称为 c1 编译器线程。服务器 JIT 编译器使用的线程称为 c2 编译器线程。

c1、c2编译线程默认大小

c1、c2 编译器线程的默认数量取决于运行应用程序的容器/设备上可用的 CPU 数量。下表汇总了 c1、c2 编译器线程的默认数量:

中央处理器 c1 线程 c2 线程
1 1 1
2 1 1
4 1 2
8 1 2
16 2 6
32 3 7
64 4 8
128 4 10

图:默认c1、c2编译线程数

您可以通过将 '-XX:CICompilerCount=N' JVM 参数传递给您的应用程序来更改编译器线程数。您在“-XX:CICompilerCount”中指定的计数的三分之一将分配给 c1 编译器线程。剩余的线程数将分配给 c2 编译器线程。假设你要使用 6 个线程(即'-XX:CICompilerCount=6'),那么 2 个线程将分配给 c1 编译器线程,4 个线程将分配给 c2 编译器线程。

c1、c2编译线程CPU消耗高——潜在解决方案

 有时您可能会看到 c1、c2 编译器线程消耗大量 CPU。当此类问题浮出水面时,以下是解决该问题的潜在解决方案:

1.什么都不做(如果是间歇性的)

在您的情况下,如果您的 C2 编译器线程的 CPU 消耗只是间歇性高而不是持续高,并且不会损害您的应用程序的性能,那么您可以考虑忽略该问题。

2.-XX:-TieredCompilation

将此 '-XX:-TieredCompilation' JVM 参数传递给您的应用程序。该参数将禁用 JIT 热点编译。因此CPU消耗会下降。但是,作为副作用,您的应用程序的性能可能会降低

3. -XX:TieredStopAtLevel=N

如果c2编译线程单独导致CPU尖峰,可以单独关闭c2编译。你可以通过'-XX:TieredStopAtLevel=3'。当你传递这个值为 3 的 '-XX:TieredStopAtLevel' 参数时,只有 c1 编译将被启用,而 c2 编译将被禁用。 

编译分为四层:

编译级别 描述
0 解释代码
1 简单的c1编译代码
2 有限的c1编译代码
3 完整的 c1 编译代码
4 C2编译代码

当您说“-XX:TieredStopAtLevel=3”时,代码将仅编译到“完整 c1 编译代码”级别。C2 编译将停止。

4. -XX:+打印编译

您可以将 '-XX:+PrintCompilation' JVM 参数传递给您的应用程序。它将打印有关您的应用程序编译过程的详细信息。它将帮助您进一步调整编译过程。

5. -XX:ReservedCodeCacheSize=N

Hotspot JIT 编译器编译/优化的代码存储在 JVM 内存的代码缓存区。此代码缓存区的默认大小为 240MB。您可以通过将“-XX:ReservedCodeCacheSize=N”传递给您的应用程序来增加它。假设您想将其设置为 512 MB,您可以这样指定:'-XX:ReservedCodeCacheSize=512m'。增加代码缓存大小有可能减少编译器线程的 CPU 消耗。

6. -XX:CICompilerCount

您可以考虑通过使用参数“-XX:CICompilerCount”来增加 C2 编译器线程。您可以捕获线程转储并将其上传到fastThread等工具,在那里您可以看到 C2 编译器线程的数量。如果您看到较少的 C2 编译器线程数并且您有更多的 CPU 处理器/内核,您可以通过指定 '-XX:CICompilerCount=8' 参数来增加 C2 编译器线程数。

点赞收藏
分类:标签:
金色梦想

终身学习。

请先登录,查看3条精彩评论吧
快去登录吧,你将获得
  • 浏览更多精彩评论
  • 和开发者讨论交流,共同进步

为你推荐

从 Linux 内核角度探秘 JDK MappedByteBuffer

从 Linux 内核角度探秘 JDK MappedByteBuffer

MappedByteBuffer VS FileChannel:从内核层面对比两者的性能差异

MappedByteBuffer VS FileChannel:从内核层面对比两者的性能差异

3
3