我最近接受了在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
如果我理解正确: -
现在我的每台服务器都运行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后,它完全释放了所有服务器的年轻一代。现在我需要帮助来理解这个特征,基本上我在假设下面是正确的吗?
我问这个,因为Full GC确实释放了所有内存,因此没有内存泄漏但是如何通过调整GC设置在内存使用和应用程序吞吐量之间取得平衡。任何人都可以通过考虑上述机器状态来提供更多的指导或推荐吗?
JVM Details:
Java Version: openjdk version "1.8.0_131" Server Class
GC: Parallel Collector(Default one)
答案 0 :(得分:2)
简而言之:如果你想了解你的系统,基本上在某个时间点进行内存使用是一个坏主意。随着时间的推移,查看行为会更有帮助。为此,请使用JConsole或专业分析器(如YourKit或JProfiler)。另一方面,Hotspot-VM的默认值是非常合理的,所以除非你有一个非常具体的应用程序内存配置文件,你可能不会通过简单地在问题上投入更多硬件来摆弄并赢得更多。
请注意,您的服务器很可能尺寸不足(请参阅问题4)
答案很长:
问题1: 对象如何通过不同的内存区域?每个对象都是在eden空间中创建的。第一个小型垃圾收集(也会触发一个主要收集)将把该对象放入幸存者(如果有足够的空间)或直接进入终身。对于已经存在于幸存者中的对象,它们从一个幸存者空间移动到另一个幸存者空间,并且在某个时刻(由VM内的启发式确定)被移动到终身。规则总是成立,至少有一名幸存者总是空着。
问题2: 对年龄大于年轻人的占有意味着,你不经常收集吗?绝对不是。如果很少执行,Java中的垃圾收集效果会更好(效率更高)。基本上,如果自上次收集以来死亡的对象越来越多,则收集效率会更高,因为它可以立即清理更多内存。 gc的设计目的是在触发full-gc之前让终端填满,直到达到非常高的填充水平(接近100%)。我们观察到生产系统几周没有完成全部gc,因为年轻一代足够大,以至于所有临时分配都在伊甸园或幸存者中死亡。除此之外:所有的缓存,Spring Beans或其他任何东西都将永久保留在终身。
问题3: 我应该调整内存参数以优化内存消耗吗?一定要:不!除非你确切地知道你正在做什么,否则永远不要碰那些东西。扩大年轻一代可能会导致您的应用程序死于内存不足错误。在摆弄这些东西之前,您应该非常清楚应用程序的长期行为,并且热点VM的启发式方法非常好。另一方面,如果你知道,你正在做什么,它可以显着减少gc次数。在一个系统(上面提到的系统)中,我们看到次要集合从一次~20秒减少到几分钟一次,并且在调整后几乎完全停止在全gcs中。但是在学习和理解的过程中,我们的应用程序如何随着时间的推移在内存方面表现得很好,我们也杀了很多命令。
问题4: 我应该增加内存而不是摆弄?取决于。您的系统不健康。增加记忆会使情况变得更糟。在具有16g物理内存的系统上运行4个VM,堆最多7g(总共28g)。如果你的所有虚拟机都将内存消耗扩大到最大值,你会看到很多交换,这肯定会将性能降低到你难以想象的水平。我会在场景中寻找更多的硬件,特别是考虑到,java应用程序的实际消耗大约是堆的1.5倍(你必须添加permgen / metaspace,堆栈,codecache和vm本身消耗的内存) )。如果您确定知道,您的应用程序正在运行-xmx7g,您可以从那里开始:增加整体内存,同时减少旧的部分,以便绝对旧的大小保持不变。然而,这意味着更多的硬件。