Linux下的Java虚拟内存使用情况,使用的内存过多

时间:2009-02-18 14:24:48

标签: java linux memory virtual-memory

我在Linux下运行的Java应用程序有问题。

当我使用默认的最大堆大小(64 MB)启动应用程序时,我看到使用tops应用程序为应用程序分配了240 MB的虚拟内存。这会在计算机上创建一些其他软件的问题,这些软件相对资源有限。

据我所知,无论如何都不会使用保留的虚拟内存,因为一旦达到堆限制,就会抛出OutOfMemoryError。我在Windows下运行相同的应用程序,我发现虚拟内存大小和堆大小相似。

无论如何,我是否可以在Linux下配置用于Java进程的虚拟内存?

编辑1 :问题不在于堆。问题是,如果我设置一个128 MB的堆,那么Linux仍然会分配210 MB的虚拟内存,这是不需要的。**

编辑2 :使用ulimit -v可以限制虚拟内存量。如果大小设置低于204 MB,则应用程序将不会运行,即使它不需要204 MB,只需64 MB。所以我想了解为什么Java需要这么多虚拟内存。这可以改变吗?

编辑3 :系统中正在运行其他几个应用程序,它们是嵌入式的。系统确实有虚拟内存限制(来自评论,重要细节)。

8 个答案:

答案 0 :(得分:588)

答案 1 :(得分:35)

Java和glibc> = 2.10存在已知问题(包括Ubuntu> = 10.04,RHEL> = 6)。

治愈就是设定这个环境。变量:

export MALLOC_ARENA_MAX=4

如果您正在运行Tomcat,则可以将其添加到TOMCAT_HOME/bin/setenv.sh文件。

对于Docker,将其添加到Dockerfile

ENV MALLOC_ARENA_MAX=4

有一篇关于设置MALLOC_ARENA_MAX的IBM文章 https://www.ibm.com/developerworks/community/blogs/kevgrig/entry/linux_glibc_2_10_rhel_6_malloc_may_show_excessive_virtual_memory_usage?lang=en

This blog post says

  已知驻留记忆以类似于a的方式蠕变   内存泄漏或内存碎片。

还有一个开放的JDK错误JDK-8193521 "glibc wastes memory with default configuration"

在Google或SO上搜索MALLOC_ARENA_MAX以获取更多参考资料。

您可能还想调整其他malloc选项以优化分配内存的低碎片:

# tune glibc memory allocation, optimize for low fragmentation
# limit the number of arenas
export MALLOC_ARENA_MAX=2
# disable dynamic mmap threshold, see M_MMAP_THRESHOLD in "man mallopt"
export MALLOC_MMAP_THRESHOLD_=131072
export MALLOC_TRIM_THRESHOLD_=131072
export MALLOC_TOP_PAD_=131072
export MALLOC_MMAP_MAX_=65536

答案 2 :(得分:9)

为Java进程分配的内存量与我的预期相当。我在嵌入式/内存有限的系统上运行Java时遇到了类似的问题。运行具有任意VM限制的任何应用程序,或者在没有足够交换量的系统上,往往会中断。它似乎是许多现代应用程序的本质,它们不是设计用于资源有限的系统。

您可以尝试更多选项并限制JVM的内存占用。这可能会减少虚拟内存占用量:

  

-XX:ReservedCodeCacheSize = 32m保留代码缓存大小(以字节为单位) - 最大值   代码缓存大小。 [Solaris 64位,   amd64和-server x86:48m;在   1.5.0_06及更早版本,Solaris 64位和64:1024m。]

     

-XX:MaxPermSize = 64m永久代的大小。 [5.0及更新版本:   64位虚拟机缩放30%; 1.4   amd64:96m; 1.3.1 -client:32m。]

此外,还应将-Xmx(最大堆大小)设置为尽可能接近应用程序的 实际峰值内存使用量 的值。我相信每次将JVM扩展到最大值时,JVM的默认行为仍然是堆大小。如果你从32M堆开始,你的应用程序达到峰值65M,那么堆将最终增长32M - > 64M - > 128M。

您也可以尝试这样做,使VM不那么积极地增加堆:

  

-XX:MinHeapFreeRatio = 40 GC到之后的最小堆空闲百分比   避免扩张。

此外,从我几年前从实验中回忆起的内容,加载的本机库数量对最小占用空间产生了巨大影响。如果我没记错的话,加载java.net.Socket增加了超过15M(我可能没有)。

答案 3 :(得分:7)

Sun JVM需要大量内存用于HotSpot,并且它映射到共享内存中的运行时库中。

如果内存是个问题,请考虑使用另一个适合嵌入的JVM。 IBM有j9,还有开源“jamvm”,它使用GNU类路径库。 Sun还在SunSPOTS上运行了Squeak JVM,因此有其他选择。

答案 4 :(得分:3)

只是一个想法,但你可以检查a ulimit -v option的影响。

这不是一个实际的解决方案,因为它会限制所有进程可用的地址空间,但这样可以让您使用有限的虚拟内存检查应用程序的行为。

答案 5 :(得分:3)

减少具有有限资源的系统堆栈的一种方法可能是使用-XX:MaxHeapFreeRatio变量。这通常设置为70,并且是GC缩小之前可用的堆的最大百分比。将其设置为较低的值,您将在例如jvisualvm分析器中看到通常将较小的堆sice用于您的程序。

编辑:要为-XX:MaxHeapFreeRatio设置小值,还必须设置-XX:MinHeapFreeRatio 例如

java -XX:MinHeapFreeRatio=10 -XX:MaxHeapFreeRatio=25 HelloWorld

EDIT2:为启动并执行相同任务的实际应用程序添加了一个示例,一个使用默认参数,另一个使用10和25作为参数。我没有注意到任何真正的速度差异,虽然理论上java应该在后一个例子中使用更多的时间来增加堆。

Default parameters

最后,最大堆是905,使用堆是378

MinHeap 10, MaxHeap 25

最后,最大堆是722,使用堆是378

这实际上有一些影响,因为我们的应用程序在远程桌面服务器上运行,许多用户可以立即运行它。

答案 6 :(得分:1)

Sun的java 1.4具有以下控制内存大小的参数:

  

-Xmsn       指定内存分配池的初始大小(以字节为单位)。   该值必须是1024的倍数   大于1MB。附上字母k   或K表示千字节,或m或M.   表示兆字节。默认   值是2MB。例子:

           -Xms6291456
           -Xms6144k
           -Xms6m
     

-Xmxn       指定内存分配池的最大大小(以字节为单位)。   该值必须是1024的倍数   大于2MB。附上字母k   或K表示千字节,或m或M.   表示兆字节。默认   值是64MB。例子:

           -Xmx83886080
           -Xmx81920k
           -Xmx80m

http://java.sun.com/j2se/1.4.2/docs/tooldocs/windows/java.html

Java 5和6还有更多。见http://java.sun.com/javase/technologies/hotspot/vmoptions.jsp

答案 7 :(得分:0)

不,您无法配置VM所需的内存量。但请注意,这是虚拟内存,不是常驻内存,因此如果不实际使用,它只会保持不受损害。

Alernatively,你可以尝试一些其他JVM,然后是Sun,内存占用更少,但我不能在这里提供建议。