JVM 为什么推荐将-Xms -Xmx值设置为相同

当我们启动应用程序时,我们指定初始内存大小和最大内存大小。对于在 JVM(Java 虚拟机)上运行的应用程序,初始和最大内存大小通过-Xms-Xmx参数指定。如果 Java 应用程序在容器上运行,则通过 '-XX: InitialRAMPercentage''-XX: MaxRAMPercentage' 参数指定。大多数企业将初始内存大小设置为低于最大内存大小的值。与这种普遍接受的做法相反,将初始内存大小设置为与最大内存大小相同具有某些更好的优势。让我们在这篇文章中讨论它们。


1. 可用性

假设您正在启动您的应用程序,初始堆大小为 2GB,最大堆大小为 24GB。这意味着当应用程序启动时,操作系统会为您的应用程序分配 2GB 内存。从那时起,随着应用程序开始处理新请求,将分配额外的内存,直到达到最大 24GB。
假设当您的应用程序的内存消耗正在从 2GB 增长到 24GB 的过程中,此时假设在您的设备中启动了一些其他进程并且它开始消耗内存。这种情况在生产/云环境中很常见,尤其是在您的应用程序与其他程序一起运行的情况下(例如自定义脚本、cron 作业、监控代理……)。

当这种情况发生时,您的应用程序将经历:

  1. ‘java.lang.OutOfMemoryError: Java heap space’
  2. 操作系统将终止您的应用程序,并显示“Out of memory: kill process or sacrifice child”。
    这意味着,您的应用程序将在事务中间崩溃。如果您的应用程序在启动期间以最大内存启动,那么您的应用程序将是安全的。操作系统只会终止新启动的脚本/ cron 作业,其内存消耗正在增长,而不是您的应用程序在启动期间内存已被完全分配。有关此问题的更多详细信息,您可以参考这篇文章

2. 性能

我们还观察到以相同的初始堆大小和最大堆大小启动的应用程序往往比以较低初始堆大小启动的应用程序执行得更好。这是一个真实的案例研究:我们采用了一个内存密集型应用程序HeapHero进行研究。此应用程序处理非常大的二进制堆转储文件并生成分析报告。在这个 HeapHero 应用程序中,我们反复分析了一个 11GB 的二进制文件,这样就会给操作系统带来内存压力。

我们进行了两个测试场景:
场景一:我们设置初始堆大小为 2GB,最大堆大小为 24GB。
场景 2:我们将初始堆大小和最大堆大小都设置为 24GB。

在场景 #1 中,我们观察到平均响应时间为 385.32 秒,
而在场景 #2 中,我们观察到平均响应时间为 366.55 秒。响应时间提高了5.11% 。响应时间的这种改进是由于两个原因而发生的:
● 来自操作系统的内存分配和释放的影响
● GC 暂停时间影响

来自操作系统的内存分配和释放

当您为初始和最大堆大小设置了不同的大小时,JVM 将不得不与操作系统协商以在需要时分配内存。同样,当应用程序在运行时对内存的需求下降时,操作系统会取走分配的内存。这种不断的分配和释放将增加应用程序的开销。
在这里插入图片描述
上图显示了场景 1 JVM 的分配和释放内存。从图中,您可以注意到内存在不断波动。您可以看到堆大小在 2GB 到 24GB 之间波动。当应用程序处理堆转储时,内存会飙升至 24GB。处理后,内存回落至 2GB。当它再次处理一个新的堆转储时,内存又回到 24GB。

图:场景 2 内存分配常量
图:场景 2 内存分配常量

上图显示了场景 2 JVM 在其生命周期内分配的内存。可以看到没有波动。在启动期间从操作系统保留内存,从那时起,没有波动。无论应用程序中的活动如何,它始终保持在 24GB。这种行为有可能在一定程度上提高应用程序的性能。

GC 暂停时间影响

当垃圾收集运行时,它会暂停您的应用程序,这将对客户产生负面影响。我们使用 GCeasy 工具研究了两种场景的垃圾收集性能。以下是结果:

设想GC 吞吐量平均 GC 暂停时间最大 GC 暂停时间
场景 1:初始堆大小设置低于最大堆大小96.59%99.2 毫秒5.23 秒
场景 1:初始堆大小设置低于最大堆大小96.59%97.0 毫秒1.65 秒

我们注意到 GC 吞吐量和 GC 暂停时间略有下降。在场景 #1 中,GC 吞吐量为 96.59%,而在场景 #2 中,GC 吞吐量稍好一些 - 97.83%。同样在场景 #1 中,Max GC 的暂停时间为 5.23 秒,而在场景 #2 中仅为 1.65 秒。


3. 应用启动时间

如果您将初始堆大小设置为与最大堆大小相同,您的应用程序的启动时间也会更好。以下是Oracle 文档的摘录:
'如果初始堆太小,Java 应用程序启动会变慢,因为 JVM 被迫频繁执行垃圾收集,直到堆增长到更合理的大小。为获得最佳启动性能,请将初始堆大小设置为与最大堆大小相同。


4.成本

无论您将初始堆大小 (-Xms) 和最大堆大小 (-Xmx) 设置为相同值还是不同值,您支付给云托管服务提供商的计算成本 ($) 都不会改变。假设您使用的是 2.2x。大型 32G RHEL 按需 AWS ec2 – 美国西部(北加利福尼亚)的实例,那么您最终将支付 0.5716 美元/小时,无论设置初始堆大小和最大堆大小的值是多少。云提供商不会根据您在该机器上使用的内存量向您收费。它们仅根据您使用实例的时间收费。因此,将初始堆大小设置为低于最大堆大小不会节省成本。


结论

在配置线程池或连接池时,将初始堆大小配置为小于最大堆大小是有意义的。在这些资源中,过度分配会产生不必要的影响,但是,内存并非如此。因此,如果您正在构建企业应用程序,您应该强烈考虑将初始堆大小和最大堆大小设置为相同的值。

原文:Benefits of setting initial and maximum memory size to the same value

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值