无法消耗整个内存

时间:2016-10-12 13:19:39

标签: 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();
    }
  }
}

启动它的命令:

 java -Xmx4096m MemoryEater1 3000

输出:

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)

最大内存和总内存之间的差异是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

为什么会这样?

2 个答案:

答案 0 :(得分:1)

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

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

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

java -Xmx4096m -XX:+UseG1GC MemoryEater1 3000

或玩一代尺寸,例如-XX:NewSize等等。

有关更多信息,请阅读here以及有关垃圾收集器算法的任何内容,例如: [GC调整]

这里快速说明了为不同代人分割内存如何使其无法使用(VM options)。 http://www.oracle.com/technetwork/java/javase/gc-tuning-6-140523.html

答案 1 :(得分:0)

可以将JVM标志设置为大于计算机上物理内存的内存量。根据目前给出的信息,您似乎很可能缺少分配此阵列的物理内存。换句话说,JVM从操作系统请求更多内存,操作系统说没有可用的内存。

另一种可能性是在您的问题的评论中注明了内存碎片问题。但是,在这种情况下,由于程序的结构,我认为不太可能。我不认为可以排除它。