Runtime.freeMemory()的问题 - Java

时间:2010-09-23 00:22:32

标签: java memory jvm runtime out-of-memory

嘿我用这段代码测试Runtime.freeMemory():

 Runtime runtime = Runtime.getRuntime();
 long freeMemory = runtime.freeMemory();

 // This is some arbitary factor that should work <= 1
 double factor = 0.8;

 int size = (int) (factor * freeMemory);
 byte[] testArray = new byte[size];

我正在创建一个大小接近freeMemory值的字节数组。出于某种原因,特别是当我将程序的内存限制在大约8MB时,代码会抛出任何因子的OutOfMemory异常&gt; 0.55。这真的没有意义,当然freeMemory意味着freeMemory,我希望它有点出来,但不是实际上是免费的双倍。

有关最新进展的任何建议吗? 感谢

(请注意,在我的测试中,我将程序可用的内存限制为8MB或16MB,使用-Xmx8M等。)

5 个答案:

答案 0 :(得分:2)

实际上,你的自由记忆分为两代:http://java.sun.com/docs/hotspot/gc1.4.2/一个是“年轻”一代,一个是“终身”一代。 如果您使用-verbose:gc -XX:+ PrintGCDetails VM设置运行,您可以看到每代生成的数量。我发现我可以完全填满我的一代,但不会超过这个。

答案 1 :(得分:0)

在使用runtime.gc()创建测试数组之前尝试进行垃圾回收。

如果你没有创建一个全新的JVM,那么每次你都可以通过不同的开始状态来获得它。


我的工作价值观&gt; 1. 1.25例如。然后我得到一个'堆空间'异常。


在这里,也许你想要'maxMemory()'。

public class Mem2 {
    public static void main(String[] args) {


        Runtime runtime = Runtime.getRuntime();
        runtime.gc();

        long freeMemory = runtime.freeMemory();

        // This is some arbitary factor that should work <= 1
        double factor = 1.29;

        int size = (int) (factor * freeMemory);
        System.out.println("      freememory is " + freeMemory);
        System.out.println("            size is " + size);
        System.out.println("the total memory is " + runtime.totalMemory());
        System.out.println("  the max memory is " + runtime.maxMemory());
        byte[] testArray = new byte[size];
    }
}

输出:

      freememory is 84466864
            size is 108962254
the total memory is 85000192
  the max memory is 129957888

Process finished with exit code 0

所以似乎有大约20M我无法解释。

我认为totalMemory()是当前由JVM分配的内存量,freeMemory()是使用了多少内存,而maxMemory()是硬限制。


您可以在代码中看到totalMemory()freememory()之间的相互作用。

public class Mem3 {

    public static void main(String[] args) {


        Runtime runtime = Runtime.getRuntime();

        for (int i = 0; true; i++) {
            runtime.gc();
            int size = i * 10000000;
            System.out.println("                 i is " + i);
            System.out.println("              size is " + size);
            System.out.println("b       freememory is " + runtime.freeMemory());
            System.out.println("b the total memory is " + runtime.totalMemory());
            System.out.println("b   the max memory is " + runtime.maxMemory());
            byte[] testArray = new byte[size];
            System.out.println("                array " + testArray.length);
            System.out.println("a       freememory is " + runtime.freeMemory());
            System.out.println("a the total memory is " + runtime.totalMemory());
            System.out.println("a   the max memory is " + runtime.maxMemory());
            System.out.println(" ");
        }

    }
}

如果你运行它并查看前后值,你可以看到发生了什么。注意在6和7之间发生的事情:

                 i is 6
              size is 60000000
b       freememory is 84300496
b the total memory is 85000192
b   the max memory is 129957888
                array 60000000
a       freememory is 24300472
a the total memory is 85000192
a   the max memory is 129957888

                 i is 7
              size is 70000000
b       freememory is 84300496
b the total memory is 85000192
b   the max memory is 129957888
                array 70000000
a       freememory is 59258168
a the total memory is 129957888
a   the max memory is 129957888

我们在6中看到,在分配60M之后,剩下大约24M。然而,在7,我们已经超过了一个门槛。已分配更多内存(注意totalMemory),freeMemory现在不到60M。

答案 2 :(得分:0)

掌握此问题的最佳方法是通过分析器运行代码,该分析器能够向您显示系统内存随时间的分配情况。如果您正在使用Eclipse,请确保已安装TPTP,我确信其他大型IDE在某处具有相同的功能。

答案 3 :(得分:0)

我认为这与堆分区的大小有关。当JVM启动时,它会将可用堆内存分成多个“空格”;例如新创建的对象有一个空间,tenured对象的空间,在第一个GC循环中存活的对象的“eden”空间,依此类推。空间的实际大小是可调的(通过JVM选项),但“新对象”空间可能远小于8Mb。

当您尝试分配包含55%报告的可用内存的数组时,内存管理器需要在“新对象”空间中找到该数量的连续内存。如果您正在获取OOME,那是因为实际的分区使得所需的连续内存量不可用......即使在GC运行之后也是如此。

基本上,您尝试使用太小的堆来运行JVM,以实现您的目标。作为一般原则,与Java的堆大小吝啬是一个坏主意。如果你给它足够的内存,你的应用程序将运行得更快(并且问题更少)。

答案 4 :(得分:0)

这个答案是基于spong在主要问题上的评论。

如果不是尝试在一个chuck中创建数组,而是将其创建分成许多较小的数组,则可以将空闲内存填充到0.98左右。

     Runtime runtime = Runtime.getRuntime();
     long freeMemory = runtime.freeMemory();

     // This is some arbitary factor that should work <= 1
     double factor = 0.8;

     int size = (int) (factor * freeMemory);


     int slice = 100;
     byte[][] testArrays = new byte[slice][1];
     for (int i = 1; i <= slice; i++) {
            testArrays[i-1] = new byte[size / slice];
            System.out.println("Allocated: " + i * size / slice);
     }

     System.out.println("Created! "+testArrays.length);