【问题标题】:Java: OutOfMemoryError Exception and freeMemory()Java:OutOfMemoryError 异常和 freeMemory()
【发布时间】:2012-01-01 06:30:57
【问题描述】:

我有以下测试程序:

public static void main(String[] args)
{       
    HashMap<Integer, String> hm = new HashMap<Integer,String>(); 
    int i = 1;  
    while(true)
    {
        hm.put(i, "blah");
        i++;
        System.out.println("############"); 
        System.out.println("Max mem: " + Runtime.getRuntime().maxMemory()); 
        System.out.println("Total mem: " + Runtime.getRuntime().totalMemory()); 
        System.out.println("Free mem:" + Runtime.getRuntime().freeMemory());
    }
}

如果我运行这个程序,我会得到以下输出:

...

    ############
    Max mem: 8060928

    Total mem: 8060928

    Free mem:334400

    Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
        at java.util.HashMap.addEntry(Unknown Source)
        at java.util.HashMap.put(Unknown Source)
        at Test.main(Test.java:14)

为什么我得到一个“OutOfMemoryError”异常,尽管方法 freeMemory() 返回有更多可用内存???如果有办法使用所有的freeMemory()?

【问题讨论】:

    标签: java exception memory out-of-memory


    【解决方案1】:

    HashMap 类有时会随着其中条目数量的增加而调整大小。即使您显示 300+K 剩余空闲空间,这也可能不足以处理哈希桶的大小调整。

    void resize(int newCapacity) {
        Entry[] oldTable = table;
        int oldCapacity = oldTable.length;
        if (oldCapacity == MAXIMUM_CAPACITY) {
            threshold = Integer.MAX_VALUE;
            return;
        }
        // ***possible big allocation here***
        Entry[] newTable = new Entry[newCapacity];
        transfer(newTable);
        table = newTable;
        threshold = (int)(newCapacity * loadFactor);
    }
    

    在更一般的意义上,不建议在 Java 中对堆内存(和整体进程大小)进行细粒度预期。堆中的一些后台分配以及尚未回收的对象占用了您可能没有预料到的空间。此外,垃圾收集器在接近满堆时会使用越来越多的 CPU。您希望以超出预期最大分配大小的大量内存开销运行。

    【讨论】:

      【解决方案2】:
      1. Runtime.freeMemory() javadoc 表示返回"an approximation to the total amount of memory currently available for future allocated objects"

      2. 所有动态结构的工作方式是它们以块的形式分配内存。当HashMap 已满时,它不会再为一个对象分配额外的空间。它分配了一些大小的块。我不知道它在 JVM 中的确切工作方式,但它可能会尝试分配两倍于它当前使用的内存量。

      【讨论】:

        【解决方案3】:

        在 HashMap 需要扩展其内部存储时,您将遇到内存不足异常。对此的要求将大于可用的感觉内存。

        【讨论】:

        • 但是当我使用 LinkedList 而不是 HashMap 时,我遇到了同样的问题。在我的真实上下文中,我想读取 1000 万条数据记录,每个记录都是一个 HashMap,我将所有 HashMap 存储在一个 LinkedList 中。 jvisualvm 告诉我,我的程序可以使用 max。 80GB,但它只使用 65GB。此时我得到了异常......
        • @user1053813,您可以这样做,但您需要为您的应用程序提供大量内存,我怀疑很多 GB。如今,内存非常便宜,因此不必成为问题。如果您希望更有效地存储数据,我会使用对象而不是 HashMap。 (可以小 2-3 倍)可能存在某种与操作系统相关的内存屏障,阻止您在一个应用程序中使用超过 64 GB。您可能会考虑使用直接内存来存储数据,这可以是对象大小的一半,并且使用很少的堆,但工作量更大。 ;)
        【解决方案4】:

        似乎可用内存量不足以运行 JVM。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-06-24
          • 2011-09-26
          • 1970-01-01
          • 2014-11-08
          • 1970-01-01
          相关资源
          最近更新 更多