【问题标题】:Huge system memory usage of java applications compared to heap usage与堆使用相比,Java 应用程序的系统内存使用量很大
【发布时间】:2016-11-08 11:51:35
【问题描述】:

我有一个类似 java 框架的微服务。许多 java 进程在单个机器上运行(ubuntu 14.04.4 LTS)。 Java 进程使用大量系统内存,因此交换空间被大量使用。 jstat gc 报告不解释系统内存使用情况。所有java进程都使用参数运行

-XX:MinHeapFreeRatio=20 -XX:MaxHeapFreeRatio=40 -XX:GCTimeRatio=4 -XX:AdaptiveSizePolicyWeight=90

强制 JVM 将内存还给系统。没有参数,问题仍然存在。一些 java 组件使用 nashorn 引擎来编写一些功能的脚本。

有人能解释一下这里的行为吗?

是否有任何 jvm 模式限制了庞大的系统内存使用?

如何命令操作系统对 jvm 的内存分配进行更多限制?

一些数据:

组件 A(带 nashorn)

顶部:

PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
2400 xxxxxx    20   0 13.933g 807496   7332 S   0.0  2.5   4180:15 java

jstat -gc 2400:

S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU    CCSC   CCSU   YGC     YGCT    FGC    FGCT     GCT
512.0  512.0   0.0   400.0  19456.0  12751.6   62464.0    59862.3   89688.0 84866.6 10624.0 9440.4 2165265 15977.896 16816 1813.836 17791.732
  • 容量:约。 180 MB
  • 用法:约。 165 MB
  • 系统资源:大约。 800 MB

为什么组件使用了 4 倍的 GC 区域内存?

组件 B(无 nashorn)

顶部:

PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
19476  xxxx     20   0 13.465g 120436   7836 S   7.0  0.4  22:40.76 java

jstat -gc 19476:

S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU    CCSC   CCSU   YGC     YGCT    FGC    FGCT     GCT
512.0  512.0   0.0    0.0   41472.0  25408.7   343040.0    7164.5   17664.0 17183.1 2048.0 1919.4   3650   10.806  939    16.788   27.594
  • 容量:约。 403 MB
  • 用法:约。 52 MB
  • 系统资源:120 MB

这里的 GC 区域容量大于实际系统内存使用量。系统内存使用量仍然是 GC 区域的两倍。 IMO 这个组件表现正常,因为库等也部分映射到内存中。

组件 C(无 nashorn)

顶部:

PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
2272 xxxxxx    20   0 13.382g 922944  11108 S   0.7  2.8  40033:41 java

jstat -gc 2272:

S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU    CCSC   CCSU   YGC     YGCT    FGC    FGCT     GCT
1024.0 1024.0 868.0   0.0   36352.0  23866.1   76800.0    56580.2   68864.0 64571.1 8448.0 7460.6 31974159 199295.501 844692 134644.040 333939.541
  • 容量:约。 190 MB
  • 用法:约。 152 MB
  • 系统资源:920 MB

为什么组件使用了 6 倍的 GC 区域内存?

【问题讨论】:

  • 没有帮助,我知道,但仍然。你知道分布式计算的第一条规则吗? 不要分发计算。我知道拥有大量小型服务可以解决很多问题,但这并不是应该在您的环境中扩展的想法。我有点不明白使用这么多不同的JVM(在同一个节点上)背后的想法,最终你会遇到这样的问题......正确的答案是使用多个节点还是使用更少的JVM?
  • 我建议查看以下给出的答案:stackoverflow.com/questions/14763079/…
  • 它与 linux/ubuntu 上的 jvm 内存管理有关。在 windows 上运行我没有观察到这些问题。 Xmx/Xms 标志限制堆大小,但对系统内存使用的影响较小。

标签: java memory memory-leaks garbage-collection jvm


【解决方案1】:

有人能解释一下这里的行为吗?

内存使用没有单一的解释,有很多因素。

  • 使用NMT 可以大致了解JVM 的各个内部部分分配了多少内存
  • 使用pmap -x <pid> 来识别内存映射文件。
  • 进行堆转储以查找直接内存缓冲区(它们只是在 pmap 中显示为一些[anon] 映射)或使用Yourkit 进行内存检查以识别直接缓冲区分配的数量。在运行时,您可以使用 BufferPoolMXBean 跟踪直接缓冲区使用情况。

除此之外,您还必须考虑到每个 JVM 都有一些基准内存消耗,并且需要为垃圾收集器提供喘息空间。在共享 JVM 中运行多个服务可以分摊这些基线成本。

由于虚拟内存系统的复杂性,您还需要了解difference between used, committed, reserved and resident memory

是否有任何 jvm 模式限制了庞大的系统内存使用?

这取决于原因。

对于托管堆,可以使用make it yield unused memory back to the OS more swiftly,但会带来性能损失。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-02-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-03
    • 2017-02-23
    • 1970-01-01
    • 2011-12-22
    相关资源
    最近更新 更多