Runtime.freeMemory() 问题 - Java

发布于 2024-09-24 17:25:51 字数 563 浏览 8 评论 0原文

嘿,我正在使用以下代码测试 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 异常。 0.55。这真的没有意义,当然 freeMemory 意味着 freeMemory,我希望它有点超出,但不会是实际免费的两倍。

对发生的事情有什么建议吗? 谢谢

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

Hey I'm testing out Runtime.freeMemory() with this code:

 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];

I'm creating a byte array of size close to the freeMemory value. For some reason, especially when I limit the memory of the program to around 8MB, the code throws an OutOfMemory exception for any factor > 0.55. This really doesnt make sense, surely freeMemory means freeMemory, I expect it to be a little out, but not double what actually is free.

Any suggestions on whats going on?
Thanks

(Note in my tests im limiting the memory available to the program to 8MB or 16MB, using -Xmx8M etc.)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

请别遗忘我 2024-10-01 17:25:51

实际上,您的空闲内存分为两代: http://java.sun.com /docs/hotspot/gc1.4.2/ 一种是“年轻”一代,一种是“终身”一代。
如果使用 -verbose:gc -XX:+PrintGCDetails VM 设置运行,您可以看到每一代需要多少时间。我发现我可以完全填补我的终身职位,但仅此而已。

Actually, your free memory divided to two generations: http://java.sun.com/docs/hotspot/gc1.4.2/ one is the "Young" generation, and one is the "tenured" generation.
If you run with -verbose:gc -XX:+PrintGCDetails VM settings, you can see how much each generation takes. I found out that I can fill my tenured generation completely, but not more than that.

夜未央樱花落 2024-10-01 17:25:51

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

如果您不是每次都创建一个全新的 JVM,那么您可能会因具有不同的启动状态而受到影响。


我的工作是为了价值观> 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。

Try garbage collecting before creating the test array with runtime.gc().

If you aren't creating a brand new JVM each time you could be getting bit by having different start states.


Mine works for values > 1. 1.25 for example. Then I get a 'heap space' exception.


Here, perhaps you want 'maxMemory()' instead.

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];
    }
}

Output:

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

Process finished with exit code 0

So there seems to be about 20M I can't account for.

I think totalMemory() is the amount of memory currently allocated by the JVM, freeMemory() is how much of this has been uses, and maxMemory() is the hard limit.


You can see the interplay between totalMemory() and freememory() with this variant on your code.

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(" ");
        }

    }
}

If you run that and look at the before and after values, you can see what's going on. Note what happens between interations 6 and 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

We see in 6 that after the allocation of 60M, there are about 24M remaining. In 7, however, we've exceeded a threshold. More memory has been allocated (note totalMemory) and freeMemory is now just under 60M.

枕头说它不想醒 2024-10-01 17:25:51

掌握这一点的最佳方法是通过分析器运行代码,该分析器能够向您显示系统中的内存如何随着时间的推移进行分配。如果您使用 Eclipse,请确保已安装 TPTP,我确信其他大型 IDE 在某处也具有相同的功能。

The best way of getting a grip on this would be to run your code through a profiler that is capable of showing you how the memory in your system is being allocated over time. If you're using Eclipse make sure you've got TPTP installed, I'm sure the other big IDEs have the same feature somewhere.

作死小能手 2024-10-01 17:25:51

我认为这与堆分区的大小有关。当JVM启动时,它会将可用的堆内存分割成许多“空间”;例如,有一个用于新创建对象的空间,一个用于长期对象的空间,一个用于在第一个 GC 周期中幸存下来的对象的“伊甸园”空间,等等。空间的实际大小是可调的(通过 JVM 选项),但“新对象”空间可能远小于 8Mb。

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

基本上,您尝试使用太小的堆来运行 JVM,而无法实现您想要执行的操作。作为一般原则,对 Java 堆大小吝惜是个坏主意。如果您为应用程序提供足够的内存,您的应用程序将运行得更快(并且问题更少)。

I think that this is to do with the sizes of the heap's partitions. When the JVM starts, it is going to split the available heap memory into a number of "spaces"; e.g. there is a space for newly created objects, a space for tenured objects, an "eden" space for objects that survive the first GC cycle, and so on. The actual sizes of the spaces are tunable (via JVM options), but the chances are that the "new objects" space is considerably less than 8Mb.

When you then try to allocate your array containing 55% of the reported free memory, the memory manager needs to find that amount of contiguous memory in the "new objects" space. If you are getting an OOME, that is because the actual partitioning is such that the required amount of contiguous memory is not available ... even after the GC has run.

Basically, you are trying to run the JVM with too small a heap for what you are trying to do. As a general principle, it is a bad idea to be miserly with Java's heap size. Your application will run faster (and with less problems) if you give it plenty of memory.

把时间冻结 2024-10-01 17:25:51

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

如果您不是尝试在一个卡盘中创建数组,而是将其创建分成许多较小的数组,则可以将可用内存填充到大约 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);

This answer is based on a comment by spong, in the main quesiton.

If rather than trying to create the array in one chuck, you split its creation into many smaller arrays, you can fill the free memory to a factor of around 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);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文