不能消耗整个内存

gri*_*dov 6 java heap-memory

我正在尝试编写一个应该占用特定大小内存的程序.我想知道的一个问题是,outOfMemory当堆中实际存在空闲空间时,我会遇到异常.

这是代码:

import java.util.Vector;
import java.lang.*;

public class MemoryEater1 {
  public static void main(String[] args) {
    try {
        long mb = Long.valueOf(args[0]);
        Vector v = new Vector();
        Runtime rt = Runtime.getRuntime();
        while (true) {
            if (v.size() > 0) {
                if (((long) v.size())*100 <  mb) {
                    System.out.println("total memory: " + rt.totalMemory()/1024/1024);
                    System.out.println("max memory: " + rt.maxMemory()/1024/1024);
                    System.out.println("free memory: " + rt.freeMemory()/1024/1024);                        
                    System.out.println("Trying to add 100 mb");                 
                    //100mb
                    byte b[] = new byte[104857600];
                    v.add(b);
                }
            } else {
                //100mb
                byte b[] = new byte[104857600];
                v.add(b);
                System.out.println("Added 100 mb");             
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

启动它的命令:

 java -Xmx4096m MemoryEater1 3000
Run Code Online (Sandbox Code Playgroud)

并输出:

total memory: 2867
max memory: 3641
free memory: 59
Trying to add 100 mb
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
        at MemoryEater1.main(MemoryEater1.java:18)
Run Code Online (Sandbox Code Playgroud)

那么最大内存和总内存之间的差异是774mb,这应该足以消耗100mb以上,但仍然存在错误,甚至机器资源足够:

[user@machine ~]$ free -m
             total       used       free     shared    buffers     cached
Mem:         15950       3447      12502          0        210       2389
-/+ buffers/cache:        847      15102
Swap:         4031 1759218603       8941
Run Code Online (Sandbox Code Playgroud)

为什么会这样?

Iva*_*van 1

我不认为这是碎片,因为你只有一个线程分配内存而不回收任何东西。

这要归咎于您的特定垃圾收集器,它们以不同的方式管理内存,从而或多或少地导致您的应用程序不可用。您可以通过分析 ) 的输出来找出使用的是哪一个java -XX:+PrintCommandLineFlags

您可以尝试使用 G1,它以不同的方式管理内存。

java -Xmx4096m -XX:+UseG1GC MemoryEater1 3000
Run Code Online (Sandbox Code Playgroud)

或者玩弄生成大小,例如-XX:NewSize等等。

有关更多信息,请阅读VM 选项和有关垃圾收集器算法的任何内容,例如 [GC 调整]

下面是一个快速说明,将内存分割为不同的代会如何使其不可用(http://www.oracle.com/technetwork/java/javase/gc-tuning-6-140523.html)。 内存布局