gpt4 book ai didi

java - 了解 JVM 内存优化

转载 作者:行者123 更新时间:2023-11-30 02:21:22 25 4
gpt4 key购买 nike

我最近承担了对 Java 服务器中的内存利用率进行基准测试和优化的任务,同时修复内存泄漏(如果有)。我们有 4 个 JVM 服务器运行在一台机器上,有 15G 物理内存和 32G 交换内存。以下是free -m快照。

              total        used        free         shared  buff/cache    available
Mem: 15289 14786 392 1 110 342
Swap: 32767 3776 28991

如果我理解正确的话:-

  1. 大部分物理内存已被使用,大部分交换内存处于空闲状态。
  2. 实际缓冲的内存量很少。
  3. 我有 48GB 虚拟内存

现在我的每台服务器都以 7G 运行,最大堆大小通过 -Xmx 选项设置。以下是 GC Utils 的输出

$ jstat -gcutil 8317
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
0.00 0.00 6.97 0.22 96.77 91.89 72 8.027 33 10.975 19.002
$ jstat -gcutil 8332
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
0.00 0.00 5.17 50.76 96.57 91.65 274 51.001 51 179.106 230.107
$ jstat -gcutil 8249
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
0.00 2.10 80.37 69.53 96.87 92.08 421 69.478 13 56.569 126.047
$ jstat -gcutil 23875
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
27.91 0.00 37.07 86.29 97.59 94.60 232 7.294 2 0.030 7.324

运行手动Full GC后,它完全释放了所有服务器的年轻代和年老代。现在我需要帮助来理解这个特征,基本上我的假设是否正确?

  1. 对象的移动取决于生命周期和存活计数,即 Eden -> S0 -> S1 -> O。
  2. 其中三台服务器的 Old Gen > Young Gen。这是否意味着 Full GC 运行得不够?
  3. 或者,我需要调整 SurvivorRatio 和 NewRatio 等设置,让年轻一代有更多机会收集对象,并延迟将对象移动到旧空间。
  4. 但是,增加 Y 空间意味着更慢的短 GC 和较差的应用程序吞吐量,我应该增加内存并不再担心调整吗?

我问这个,因为Full GC确实释放了所有内存,所以不存在内存泄漏,但是如何通过调整GC设置在内存使用和应用程序吞吐量之间取得平衡。任何人都可以通过考虑上述机器状态来提供更多指导或建议吗?

JVM Details:
Java Version: openjdk version "1.8.0_131" Server Class
GC: Parallel Collector(Default one)

最佳答案

简而言之:如果您想了解您的系统,基本上了解某个时间点的内存使用情况是一个坏主意。随着时间的推移观察行为会更有帮助。为此,请使用 JConsole 或专业分析器(如 YourKit 或 JProfiler)。另一方面,Hotspot-VM 的默认设置非常合理,因此除非您有非常具体的应用程序内存配置文件,否则您可能不会通过摆弄来赢得很多,而通过简单地投入更多硬件来解决问题可能不会赢得更多。

请注意,您的服务器很可能尺寸不足(请参阅问题 4)

长答案:

问题 1: 对象如何在不同的内存区域中进行处理?每个对象都是在 eden 空间中创建的。第一个次要垃圾收集(也会触发主要收集)会将该对象放入幸存者中(如果有足够的空间)或直接放入终身对象中。对于已经在幸存者中的对象,它们从一个幸存者空间移动到另一个,并在某个时刻(由虚拟机内的启发式确定)被移动到终身。规则始终成立,至少有一个幸存者始终是空的。

问题 2: 老年人比年轻人从事更多的工作是否意味着您收集的频率不够?绝对不是。如果很少执行,Java 中的垃圾收集效果会更好(更高效)。基本上,如果自上次收集以来有更多对象死亡,则收集会更有效,因为它可以一次清理更多内存。 gc 的设计目的是让 tenured 填满,直到达到非常高的填充水平(接近 100%),然后再触发 full-gc。我们观察到生产系统数周内都没有进行 full-gc,因为年轻代足够大,因此所有临时分配都会在 eden 或 Survivor 中消亡。除此之外:您的所有缓存、Spring Beans 或其他任何内容都将始终处于长期状态。

问题 3: 我应该调整内存参数以优化内存消耗吗? 无论如何:不!除非你确切地知道自己在做什么,否则永远不要碰那些东西。扩大年轻代可能会导致您的应用程序因内存不足错误而终止。在摆弄这些东西之前,您应该非常清楚应用程序的长期行为,并且热点虚拟机的启发式方法非常好。另一方面,如果您知道自己在做什么,则可以显着减少 gc 时间。在一个系统(上面提到的那个)中,我们看到次要收集从大约 20 秒一次减少到几分钟一次,并且在调整后 full-gc 几乎完全停止。但在学习和理解我们的应用程序随着时间的推移如何在内存方面表现的过程中,我们也杀死了很多执行。

问题 4: 我应该增加内存而不是摆弄吗? 视情况而定。您的系统并不健康。增加内存会使情况变得更糟。您在物理内存为 16g 的系统上运行 4 个虚拟机,堆容量高达 7g(总共 28g)。如果所有虚拟机都将内存消耗扩大到最大,您将看到大量交换,这肯定会将性能降低到您难以想象的水平。在这种情况下,我会选择更多的硬件,特别是考虑到 java 应用程序的实际消耗大约是堆的 1.5 倍(您必须添加 permgen/metaspace、堆栈、代码缓存和 vm 本身消耗的内存) )。如果您确定,您的应用程序正在使用 -xmx7g 运行,您可以从这里开始:增加总体内存,同时减少旧代部分,以便绝对旧大小保持不变。然而,这意味着需要更多的硬件。

关于java - 了解 JVM 内存优化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46727858/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com