什么在java进程中消耗内存?

Kon*_* S. 21 linux memory java

我们正在尝试调查中等负载下 java 进程的内存使用情况。

  PID   USER    PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
  12663 test    20   0 8378m 6.0g 4492 S   43  8.4 162:29.95 java
Run Code Online (Sandbox Code Playgroud)

如您所见,我们的常驻内存为 6Gb。现在有趣的部分是:这个过程是用这些参数执行的:

  • -Xmx2048m
  • -Xms2048m
  • -XX:NewSize=512m
  • -XX:MaxDirectMemorySize=256m
  • ... 其他一些用于 GC 和其他东西

查看这些设置和实际内存使用情况,我们偶然发现了我们期望此进程使用的内容与它实际使用的内容之间的差异。

通常我们的内存问题是通过分析堆转储来解决的,但在这种情况下,我们的内存是在堆外的某个地方使用的。

问题:尝试找出如此高内存使用率的原因的步骤是什么?哪些工具可以帮助我们识别在该过程中使用内存的内容?

编辑 0

看起来这不是堆相关的问题,因为我们仍然有相当多的空间:

jmap -heap 12663
Run Code Online (Sandbox Code Playgroud)

结果(编辑以节省空间)

Heap Configuration:
MinHeapFreeRatio = 40
MaxHeapFreeRatio = 70
MaxHeapSize      = 2147483648 (2048.0MB)
NewSize          = 536870912 (512.0MB)
MaxNewSize       = 536870912 (512.0MB)
OldSize          = 1610612736 (1536.0MB)
NewRatio         = 7
SurvivorRatio    = 8
PermSize         = 21757952 (20.75MB)
MaxPermSize      = 85983232 (82.0MB)

New Generation: 45.7% used
Eden Space: 46.3% used
From Space: 41.4% used
To Space: 0.0% used
concurrent mark-sweep generation: 63.7% used
Perm Generation: 82.5% used
Run Code Online (Sandbox Code Playgroud)

编辑 1

使用 pmap 我们可以看到有相当多的 64Mb 分配:

pmap -x 12663 | grep rwx | sort -n -k3 | less
Run Code Online (Sandbox Code Playgroud)

结果是:

... a lot more of these 64Mb chunks
00007f32b8000000       0   65508   65508 rwx--    [ anon ] <- what are these?
00007f32ac000000       0   65512   65512 rwx--    [ anon ]
00007f3268000000       0   65516   65516 rwx--    [ anon ]
00007f3324000000       0   65516   65516 rwx--    [ anon ]
00007f32c0000000       0   65520   65520 rwx--    [ anon ]
00007f3314000000       0   65528   65528 rwx--    [ anon ] 
00000000401cf000       0  241904  240980 rwx--    [ anon ] <- Direct memory ?
000000077ae00000       0 2139688 2139048 rwx--    [ anon ] <- Heap ?
Run Code Online (Sandbox Code Playgroud)

那么如何找出那些 64Mb 的块是什么?什么在使用它们?他们里面有什么样的数据?

谢谢

Chr*_*ian 24

该问题可能与此glibc 问题有关

基本上,当您有多个线程分配内存时,glibc 会增加可用的 arenas 的数量来进行分配以避免锁争用。竞技场是 64Mb 大。上限是创建核心竞技场数量的8倍。当一个线程访问一个已经被锁定的竞技场时,竞技场将按需创建,因此它会随着时间的推移而增长。

在使用线程的 Java 中,这会很快导致创建大量的竞技场。并且在这些领域都有分配。最初,每个 64Mb arena 只是映射未提交的内存,但是当您进行分配时,您开始为它们使用实际内存。

您的 pmap 可能有与下面类似的列表。注意 324K + 65212K = 65536K、560K + 64976K == 65536K、620K + 64916K == 65536K。也就是说,它们的总和为 64Mb。

00007f4394000000 324K rw--- [匿名]
00007f4394051000 65212K ----- [匿名]
00007f4398000000 560K rw--- [匿名]
00007f439808c000 64976K ----- [匿名]
00007f439c000000 620K rw--- [匿名]
00007f439c09b000 64916K ----- [匿名]

至于解决方法:该错误提到了一些您可以设置的环境参数来限制 arenas 的数量,但是您需要一个足够高的 glibc 版本。

  • 将 Xmx 和 Xms 设置为相同的值,并在启动我们的 Web 服务的 sh 脚本中设置环境变量“export MALLOC_ARENA_MAX=4”对我们的案例有帮助。在此之前,我们每 2 到 8 小时就会经历一次由于 OOM Killer 导致的 Web 服务重启。Ubuntu 14.04 中的 GLIBC 版本是 2.19,这很好,因为它需要 &gt;= 2.16 才能使 MALLOC_ARENA_MAX 设置工作 (5认同)

Jan*_*nen 3

Lamdba 探针怎么样?除此之外,它还可以向您显示内存使用情况细分,类似于下面的屏幕截图:

Lambda Probe 内存使用情况视图

有时pmap -x your_java_pid也能有所帮助。