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


20

我们正在尝试研究中等负载下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

如您所见,我们的常驻内存为6Gb。现在有趣的部分是:使用以下参数执行流程:

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

在查看这些设置和实际内存使用量时,我们迷迷糊糊地看到了我们期望此过程使用的内容与实际使用的内容之间的差异。

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

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

编辑0

看起来这不是一个与堆相关的问题,因为我们那里还有很多空间:

jmap -heap 12663

结果(编辑以节省空间)

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

编辑1

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

pmap -x 12663 | grep rwx | sort -n -k3 | less

结果是:

... 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 ?

那么如何找出那些64Mb块呢?什么在使用它们?它们中包含什么样的数据?

谢谢


2
我遇到了完全一样的问题...这是我的问题。stackoverflow.com/questions/18734389/…您对此有解决方案吗?
DeepNightTwo 2013年

Answers:


21

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

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

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

您的pmap可能具有类似于以下内容的列表。注意324K + 65212K = 65536K,560K + 64976K == 65536K,620K + 64916K == 65536K。也就是说,它们总计高达64Mb。

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

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


5
将Xmx和Xms设置为相同的值,并在启动我们的Web服务的sh脚本中设置环境变量“ export MALLOC_ARENA_MAX = 4”对我们而言是有帮助的。在此之前,由于OOM Killer每2到8小时都会重启一次Web服务。Ubuntu 14.04中的GLIBC版本是2.19,这很好,因为MALLOC_ARENA_MAX设置需要> = 2.16才能起作用
Kluyg 2015年

这个答案和上面的评论对我来说是一个救命稻草。就我而言,MALLOC_ARENA_MAX = 1是必要且有效的。
约翰·巴希尔

3

如何Lamdba探头?除其他功能外,它还可以显示类似于以下屏幕截图的内存使用情况细分:

Lambda Probe内存使用情况视图

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


感谢您的回答。如果我理解正确,那么Lambda Probe是否适用于Apache Tomcat?我们不使用...关于pmap,我会将信息添加到顶部帖子
Konstantin S.

2

JProfiler可能是您想要的东西,但它不是免费的。另一个用于调查Java进程内存使用情况的好工具是免费的Java VisualVM,它在Oracle / Sun JDK发行版中作为JDK工具提供。我个人建议使用更全面的方法来解决该问题(即监视JDK + OS +磁盘等)–使用某些网络监视系统-Nagios,Verax NMS或OpenNMS。


2
他的泄漏非常严重,因此JProfiler并不能为您带来真正的帮助
Asaf Mesika

2

问题出在堆之外,因此最佳候选人是:

JNI leak  
Allocation of direct memory buffer

由于您限制了直接缓冲区的大小,因此我认为最好的选择是JNI泄漏。


1

有一个方便的工具可以查看JDK中包含的堆内存分配(称为jmap),除此之外,您还可以使用堆栈等(Xss)。运行以下两个jmap命令以获取有关内存使用情况的更多信息:

jmap -heap <PID>
jmap -permstat <PID>

要获得更多甚至更多的信息,您可以使用jconsole(也包含在JDK中)连接到该进程。但是,Jconsole要求在应用程序中配置JMX。


感谢您的回答,但问题似乎出在堆之外。我将更新最新文章,以反映jmap的一些信息
Konstantin S.

该进程有多少个线程?在大多数平台上,堆栈大小默认为2MB,因此请乘以线程数。如果它占所有“丢失”的内存,但可能占其中的一部分,我会感到惊讶。
HampusLi 2011年

从pmap获取的信息大约有300个线程,我们的堆栈大小为1Mb。从相同的pmap输出来看,这些堆栈看起来都不使用超过100Kb
Konstantin S.

0

使用JVisualVM。它具有各种不同的视图,这些视图将告诉您正在使用多少堆内存,PermGen等。

至于回答你的问题。Java处理内存的方式与您期望的完全不同。

设置-Xms和-Xmx参数时,您在告诉JVM它应该在堆中开始分配多少内存,以及它应该分配的最大内存。

如果您有一个Java应用程序使用了总共​​1m的内存,但传入了-Xms256m -Xmx2g,那么JVM将使用256m的使用内存进行初始化。它不会使用少于那个。您的应用程序仅使用1m的内存并不重要。

其次。在上述情况下,如果您的应用在某个时候使用了超过256m的内存,那么JVM将分配必要的内存以服务请求。但是,它不会将堆大小降回最小值。至少在大多数情况下不是这样。

在您的情况下,由于将最小和最大内存设置为2g,因此JVM会在开始时分配2g并维护它。

Java内存管理非常复杂,调整内存使用量本身就是一项任务。但是,那里有很多资源可能会有所帮助。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.