Java 中,我们可以使用 JVM 参数在 docker 中获得最佳性能。
常用办法:
- 设置访问内存参数
- 设置垃圾收集器
- 设置最小和最大堆空闲比率
访问内存参数
为了获得良好的内存性能,我们可以通过在运行 Java 应用程序时将自定义值传递给某些标志来覆盖 JVM 内存参数的默认值:
-Xms:-Xms 标志的值确定 Java 堆的初始值或最小值,默认是物理内存的1/64。它可用于应用程序需要比 JVM 的默认最小值更多的内存的情况。
-Xmx:与 -Xms 类似,-Xmx 标志可用于设置 Java 应用程序的堆空间最大值,默认是物理内存的1/4。当我们想要故意限制应用程序的内存量时,可以使用它。
请记住,-Xms 值必须等于或小于 -Xmx 值。应将其设置为 -Xmx 值以获得最佳结果。
默认空余堆内存小于 40%时,JVM就会增大堆直到-Xmx的最大限制;空余堆内存大于70%时,JVM会减少堆直到-Xms的最小限制。因此服务器一般设置-Xms、 -Xmx相等以避免在每次GC 后调整堆的大小。可以利用JVM提供的-Xmn -Xms -Xmx等选项可进行堆内存设置,一般的要将-Xms和-Xmx选项设置为相同,而-Xmn为1/4的-Xmx值,建议堆的最大值设置为可用内存的最大值的80%。
如何决定:
假设我们有一个容器,它被分配了 2GB 内存。因此,我们必须将 -Xms 和 -Xmx 值设置为 1280。我怎么知道?好吧,我有自己的方法来找出我通过测试和经验发现的:
您可以将实际分配的内存除以 1.6。 x/1.6 = 值。 2048 / 1.6 = 1280。
Runtime#maxMemory 方法返回与 JVM 尝试使用的内存一样多的内存。一旦 JVM 内存使用量达到此水平,它将停止分配更多内存,而是增加垃圾收集频率。
如果 JVM 对象在垃圾收集器运行后仍然需要更多内存,则 JVM 可能会抛出 java.lang.OutOfMemoryError 运行时异常。
参考:https://www.baeldung.com/java-heap-memory-api
垃圾收集器
JVM 中有四个可用的垃圾收集器。垃圾收集器之间的应用程序吞吐量和应用程序暂停可能不同。应用程序吞吐量是指 Java 应用程序运行的速度,而应用程序暂停是指垃圾收集器清理未使用内存所需的时间。
- 串行垃圾收集器
- 并行垃圾收集器
- CMS垃圾收集器
- G1 垃圾收集器
在这里,我们将讨论 G1 垃圾收集器。 首先,我想通知您,当 JVM 执行 GC 时,它会暂停应用程序,这意味着它不会在 GC 期间工作或卡住。因此,对于 GC 何时启动以及需要多长时间,我们必须非常谨慎。
G1 是一个 stop-the-world 和 evacuating 垃圾收集器,它是分代的、渐进的、并行的、经常并发的,并在每个 stop-the-world 暂停中跟踪暂停时间目标。G1 将堆划分为(虚拟)年轻代和年老代,就像其他收集器一样。空间开垦活动主要针对年轻一代,因为这是最有效的方式,老一代的空间开垦在某些情况下会发生。
为了提高吞吐量,某些操作通常在 stop-the-world 暂停中完成。如果应用程序停止,其他需要更长时间的操作(例如全局标记等全堆操作)与应用程序并行运行。
G1 主要通过疏散来检索空间,这涉及通过将选定内存区域中的对象直接复制到新内存区域来压缩它们。在疏散完成后,先前由活动对象占用的空间被重新用于应用程序的分配。
垃圾优先收集器不会实时收集。它以很高的概率尝试在更长的时间内达到设定的暂停时间目标,但对于给定的暂停并不总是完全确定。
您可以通过在命令行上提供 **-XX:+UseG1GC **来显式启用它。
图中显示:在高负载下收缩默认 GC 触发多个 GC 周期并引入延迟
参考:java垃圾回收器
最小和最大堆空闲比率
影响垃圾收集性能的两个最重要的因素是总可用内存和专用于年轻代的堆的比例。
如果您想减少应用程序的动态内存占用(它在执行期间使用的 RAM 量),您可以通过减少 Java 堆大小来实现。Java SE Embedded 应用程序可能需要这样做。
通过使用命令行选项 「-XX:MaxHeapFreeRatio 和 -XX:MinHeapFreeRatio 降低选项 -XX:MaxHeapFreeRatio(默认值为 70%)和 -XX:MinHeapFreeRatio(默认值为 40%」 的值来最小化 Java 堆大小。将 -XX:MaxHeapFreeRatio 降低至低至 10% 并将 -XX:MinHeapFreeRatio 降低至 5% 已证明可以成功减少堆大小而不会造成太多性能下降;但是,结果可能会因您的应用程序而有很大差异。为这些参数尝试不同的值,直到它们尽可能低,但它们仍保持可接受的性能。
参考
因此,如果我们有一个 2GB 内存的 docker 容器,则基于上述参数,我们可以使用以下 java 参数运行 java 应用程序。
java -Xms1250M -Xmx1250M -XX:+UseG1GC -
XX:+UseStringDeduplication -XX:MinHeapFreeRatio=5 -XX:MaxHeapFreeRatio=10 -jar java-application