虚拟内存使用从Linux在Linux下使用太多内存

问题:

我在Linux下运行的Java应用程序有问题。
当我启动应用程序时,使用默认的最大堆大小(64mb),我看到使用top应用程序,240 MB的虚拟内存被分配给应用程序。这在计算机上的一些其他软件产生一些问题,这是相对资源有限的。
根据我的理解,保留的虚拟内存不会被使用,因为一旦达到堆限制,抛出一个OutOfMemoryError。我在Windows下运行相同的应用程序,我看到虚拟内存大小和堆大小是相似的。
有没有办法在Linux下配置Java进程中使用的虚拟内存?
编辑1:问题不是堆。问题是,如果我设置一个128M的堆,例如,仍然linux分配210 MB的虚拟内存,这是不需要的。
编辑2:使用ulimit -v可以限制虚拟内存的数量。如果大小设置低于204 MB,那么应用程序不会运行,即使它不需要204MB,只有64MB。所以我想了解为什么java需要这么多的虚拟内存。这可以改变吗
编辑3:系统中运行的其他几个应用程序是嵌入式的。并且系统确实存在虚拟内存限制。 (来自评论,重要细节)

回答:

这是对Java的长期投诉,但它基本上没有意义,通常是基于错误的信息。通常的措辞就像“Hello World on Java需要10兆字节!为什么需要它?那么这里有一种方法可以让64位JVM的“Hello World”声称至少要通过一种测量形式来占用4千兆字节。

java -Xms1024m -Xmx4096m com.example.Hello

不同的测量记忆方式

在Linux上,top命令为您提供了几个不同的内存号。这是关于Hello World的例子:

PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
2120 kgregory 20 0 4373m 15m 7152 S 0 0.2 0:00.10 java

  • VIRT是虚拟内存空间:虚拟内存映射中所有内容的总和(见下文)。这是非常无意义的,除非它不是(见下文)。
  • RES是驻留集大小:当前驻留在RAM中的页数。在几乎所有的情况下,这是唯一的数字,你应该用来说“太大”。但是它还不是很好的数字,特别是在谈论Java时。
  • SHR是与其他进程共享的驻留内存量。对于Java进程,这通常限于共享库和内存映射的JAR文件。在这个例子中,我只运行一个Java进程,所以我怀疑7k是操作系统使用的库的结果。
  • 默认情况下,SWAP未打开,此处不显示。它表示当前驻留在磁盘上的虚拟内存量whether or not it’s actually in the swap space。操作系统对于将活动页保留在RAM中非常好,唯一的交换方法是(1)购买更多的内存,或者(2)减少进程数,所以最好忽略这个数字。

Windows任务管理器的情况有点复杂。在Windows XP下,有“内存使用量”和“虚拟内存大小”列,但是official documentation对它们的含义毫无保留。 Windows Vista和Windows 7添加更多列,实际上是documented。其中,“工作集”衡量是最有用的;它大致对应于Linux上的RES和SHR的总和。

了解虚拟内存映射

进程消耗的虚拟内存是进程内存映射中的所有内容的总和。这包括数据(例如,Java堆),还包括程序使用的所有共享库和内存映射文件。在Linux上,您可以使用pmap命令来查看映射到进程空间的所有东西(从这里开始,我只会参考Linux,因为这是我使用的;我确定有相当的Windows的工具)。以下是“Hello World”程序的内存映射的摘录;整个内存映射长度超过100行,并且有一千行列表是不寻常的。

0000000040000000 36K r-x– /usr/local/java/jdk-1.6-x64/bin/java
0000000040108000 8K rwx– /usr/local/java/jdk-1.6-x64/bin/java
0000000040eba000 676K rwx– [ anon ]
00000006fae00000 21248K rwx– [ anon ]
00000006fc2c0000 62720K rwx– [ anon ]
0000000700000000 699072K rwx– [ anon ]
000000072aab0000 2097152K rwx– [ anon ]
00000007aaab0000 349504K rwx– [ anon ]
00000007c0000000 1048576K rwx– [ anon ]

00007fa1ed00d000 1652K r-xs- /usr/local/java/jdk-1.6-x64/jre/lib/rt.jar

00007fa1ed1d3000 1024K rwx– [ anon ]
00007fa1ed2d3000 4K —– [ anon ]
00007fa1ed2d4000 1024K rwx– [ anon ]
00007fa1ed3d4000 4K —– [ anon ]

00007fa1f20d3000 164K r-x– /usr/local/java/jdk-1.6-x64/jre/lib/amd64/libjava.so
00007fa1f20fc000 1020K —– /usr/local/java/jdk-1.6-x64/jre/lib/amd64/libjava.so
00007fa1f21fb000 28K rwx– /usr/local/java/jdk-1.6-x64/jre/lib/amd64/libjava.so

00007fa1f34aa000 1576K r-x– /lib/x86_64-linux-gnu/libc-2.13.so
00007fa1f3634000 2044K —– /lib/x86_64-linux-gnu/libc-2.13.so
00007fa1f3833000 16K r-x– /lib/x86_64-linux-gnu/libc-2.13.so
00007fa1f3837000 4K rwx– /lib/x86_64-linux-gnu/libc-2.13.so

格式的快速说明:每一行以片段的虚拟内存地址开始。这之后是段的大小,权限和段的来源。最后一个项目是一个文件或“anon”,它表示通过mmap分配的内存块
从顶部开始,我们有

  • JVM加载器(即,键入java时运行的程序)。这很小所有这些都是在存储真实JVM代码的共享库中加载。
  • 一堆持有Java堆和内部数据的anon块。这是一个Sun JVM,所以堆被分成多代,每个都是自己的内存块。请注意,JVM根据-Xmx值分配虚拟内存空间;这允许它有一个连续的堆。内部使用-Xms值来说明程序启动时堆中有多少“正在使用”,并在接近限制时触发垃圾收集。
  • 一个内存映射的JAR文件,在这种情况下是持有“JDK类”的文件。当您记忆映射JAR时,您可以非常有效地访问其中的文件(从每次开始读取它)。 Sun JVM将记录映射类路径中的所有JAR;如果您的应用程序代码需要访问JAR,那么还可以对其进行内存映射。
  • 两线程的每线程数据。 1M块是一个线程栈;我不知道进入4K块。对于一个真实的应用程序,您将看到几十个,如果不是数百个这些条目通过内存映射重复。
  • 其中一个拥有实际JVM代码的共享库。其中有几个。
  • C标准库的共享库。这只是JVM加载的不是Java的一部分的许多事情之一。

共享库特别有趣:每个共享库至少有两个段:包含库代码的只读段和包含库的全局每过程数据的读写段(我不知道什么是没有权限的段落;我只在x64 Linux上看到它)。库的只读部分可以在使用库的所有进程之间共享;例如,libc具有1.5M的可以共享的虚拟内存空间。

什么时候是虚拟内存大小重要?

虚拟内存映射包含很多东西。其中一些是只读的,其中一些是共享的,其中一些被分配但从未被触摸(例如,在这个例子中几乎所有的4Gb的堆)。但是操作系统足够聪明,只能加载所需的内存,所以虚拟内存大小在很大程度上是无关紧要的。
虚拟内存大小很重要的是,如果您运行在32位操作系统上,那么您只能在进程地址空间中分配2Gb(或某些情况下,3Gb)。在这种情况下,您正在处理一个稀缺的资源,可能必须进行权衡,例如减小堆大小,以便内存映射大型文件或创建大量线程。
但是,考虑到64位机器是普遍存在的,我认为在虚拟内存大小是完全不相关的统计数据之前不会很久。

什么时候居民设置大小重要?

居民设置大小是实际上在RAM中的虚拟内存空间的那部分。如果您的RSS增长是整个物理内存的重要部分,那么可能是开始担心的时候了。如果您的RSS增长以占用您的所有物理内存,并且您的系统开始交换,那么过去的时间开始令人担忧。
但RSS也是误导的,特别是在轻装机器上。操作系统不会花费大量时间来回收进程使用的页面。这样做有一点好处,如果这个过程在将来会触发页面,那么潜在的页面错误就会出现。因此,RSS统计信息可能包括许多未被积极使用的页面。

底线

除非交换,否则不要过分关注各种内存统计信息告诉你什么。有一点值得注意的是,越来越多的RSS可能表示某种内存泄漏。
使用Java程序,更重要的是要注意堆中发生的情况。消耗的空间总量很重要,您可以采取一些步骤来减少。更重要的是在垃圾收集中花费的时间,以及堆的哪些部分被收集。
访问磁盘(即数据库)是昂贵的,并且内存便宜。如果你可以交换另一个,这样做。

 
 
Code问答: http://codewenda.com/topics/python/
Stackoverflow: Virtual Memory Usage from Java under Linux, too much memory used

*转载请注明本文链接以及stackoverflow的英文链接

发表评论

电子邮件地址不会被公开。 必填项已用*标注

63 − 59 =