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

Nar*_*mar 5 java memory-management ubuntu ulimit

我正在尝试强制执行程序在 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....");
  }
}
Run Code Online (Sandbox Code Playgroud)

默认情况下,我的 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
Run Code Online (Sandbox Code Playgroud)

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

ulimit -v 524288
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

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

Error occurred during initialization of VM
Could not reserve enough space for object heap
Could not create the Java virtual machine.
Run Code Online (Sandbox Code Playgroud)

理想情况下,它不应该发生,因为我的 Java 程序只占用大约 128MB 的内存,这完全在我指定的 ulimit 参数范围内。如果我将参数更改为我的 Java 程序,如下所示:

java -Xmx256m EatMem
Run Code Online (Sandbox Code Playgroud)

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

java -Xmx800m EatMem
Run Code Online (Sandbox Code Playgroud)

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

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

小智 3

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

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


如果我设置ulimit -v 524288并尝试做

运行正常

java -mx64m -version
java -mx128m -version
java -mx256m -version
Run Code Online (Sandbox Code Playgroud)

由于 malloc 失败而崩溃

java -mx300m -version
Run Code Online (Sandbox Code Playgroud)

VM初始化期间发生错误

java -mx400m -version
java -mx512m -version
Run Code Online (Sandbox Code Playgroud)

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