为什么使用 ulimit -v 将虚拟内存限制为 512MB 会导致 JVM 崩溃?

为什么使用 ulimit -v 将虚拟内存限制为 512MB 会导致 JVM 崩溃?

我正在尝试强制执行程序在 Unix 系统上可以消耗的最大内存。我认为 ulimit -v 应该可以解决问题。这是我为测试编写的一个示例 Java 程序:

import java.util.*;
import java.io.*;

public class EatMem {

  public static void main(String[] args) throws IOException, InterruptedException {
    System.out.println("Starting up...");
    System.out.println("Allocating 128 MB of Memory");
    List<byte[]> list = new LinkedList<byte[]>();
    list.add(new byte[134217728]); //128 MB
    System.out.println("Done....");
  }
}

默认情况下,我的 ulimit 设置是(ulimit -a 的输出):

core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 31398
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 31398
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

当我执行 Java 程序 (java EatMem) 时,它执行没有任何问题。现在我尝试通过启动以下命令将当前 shell 中启动的任何程序的最大可用内存限制为 512MB:

ulimit -v 524288

ulimit -a 输出显示限制设置正确(我认为):

core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 31398
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 31398
virtual memory          (kbytes, -v) 524288
file locks                      (-x) unlimited

如果我现在尝试执行我的 java 程序,它会给出以下错误:

Error occurred during initialization of VM
Could not reserve enough space for object heap
Could not create the Java virtual machine.

理想情况下,这种情况不应该发生,因为我的 Java 程序仅占用大约 128MB 的内存,这完全在我指定的 ulimit 参数之内。如果我将 Java 程序的参数更改为如下形式:

java -Xmx256m EatMem

该程序再次正常运行。尝试提供比 ulimit 限制更多的内存时,例如:

java -Xmx800m EatMem

导致预期的错误。为什么设置 ulimit 后,程序在第一种情况下执行失败?

我已经在 Ubuntu 11.10 和 12.0.4 上使用 Java 1.6 和 Java 7 进行了上述测试

答案1

ulimit -v设置程序可以使用的最大地址空间。这包括所有共享内存,如库、线程堆栈空间、直接内存等。由于 JVM 并非设计为在这种有限的虚拟内存环境中运行,因此它可能无法以最佳方式布局。也就是说,因为虚拟内存通常非常非常便宜。我怀疑您必须将此值设置得更高才能使 JVM 运行。

顺便说一句:JVM 在启动时分配最大堆大小。


如果我决定ulimit -v 524288并尝试做

运行正常

java -mx64m -version
java -mx128m -version
java -mx256m -version

由于 malloc 失败而崩溃

java -mx300m -version

VM 初始化过程中发生错误

java -mx400m -version
java -mx512m -version

这或多或少是预期的行为。

相关内容