运行时 - 为什么 freeMemory() 没有正确显示内存消耗? [英] Runtime - why is freeMemory() not showing memory consumed correctly?

查看:97
本文介绍了运行时 - 为什么 freeMemory() 没有正确显示内存消耗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

下面是检查内存的代码片段

公共类 TestFreeMemory {公共静态无效主(字符串...参数){运行时 rt = Runtime.getRuntime();System.out.println("空闲内存(GC前):" + rt.freeMemory());rt.gc();System.out.println("空闲内存(GC1之后):" + rt.freeMemory());rt.gc();//第二次确保结果一致//可能已经收集了所有不可访问的对象System.out.println("空闲内存(GC2之后):" + rt.freeMemory());String s = new String("abcd");整数 i = 新整数(12345);System.out.println("空闲内存(创建字符串后):" + rt.freeMemory());//为什么 freeMemory 没有反映两个对象消耗的内存}}

输出是

空闲内存(GC前):1859672可用内存(GC1 之后):1911768可用内存(GC2 之后):1911768可用内存(创建字符串后):1911768

为什么 freeMemory 没有反映两个对象消耗的内存?

<小时>

更清楚地说,问题是关于 getMemory() 调用没有显示预期结果,即使创建了两个对象并且与 GC 无关.进行了两次 GC 调用只是为了确保 getMemory() 调用的数量是正确的..顺便说一句,创建对象后没有 GC 调用.. 所以请注意,我不是在创建对象后尝试 GC..

解决方案

HotSpot JVM 上的内存管理:

<块引用>

另一个理想的垃圾收集器特点是限制碎片化.当记忆为垃圾对象被释放,自由空间可能会出现在小块中各个领域,以便可能没有足够的空间在任何一个将用于的连续区域大对象的分配. 一消除碎片化的方法被称为压缩,在其中讨论各种垃圾收集器设计下面的选择.

HotSpot JVM 中的内存管理(PDF 格式).

此行为可能非常依赖于垃圾收集的特定实现.例如:

<块引用>

Parallel Mark Compact

  • 停止世界
  • 堆分成固定大小的块(现在> 2kb,可能会增加或符合人体工程学)
  • 块是实时数据汇总的单位
  • 平行标记
  • 在外部位图中记录实时数据地址
  • 查找每个块的实时数据大小
  • 找到密集的块,即那些(几乎)充满活动对象的块

<小时>

我已经制作了这个示例(使用滥用字符串连接来占用更多内存):

公共类 TestFreeMemory {静态无效分配一些内存(){long[][] array = new long[400][400];}公共静态无效主(字符串...参数){运行时 rt = Runtime.getRuntime();分配一些内存();//一旦我们离开,我们的数组将不再可达System.out.println("空闲内存(GC前):" + rt.freeMemory());rt.gc();System.out.println("空闲内存(GC后):" + rt.freeMemory());String a = new String("A");for(int i = 0; i <100; i++){a+="B";}System.out.println("空闲内存(创建字符串后):" + rt.freeMemory());//预期可用内存较少.}}

输出:

<块引用>

空闲内存(GC前):3751800

空闲内存(GC 后):5036104

空闲内存(创建字符串后):5012048

<小时>

如果我在循环中使用相对较少的迭代次数(比如 10 次),额外的空间不会出现在 freeMemory() 中,我会得到如下结果:<块引用>

空闲内存(GC前):3751800

空闲内存(GC 后):5036040

空闲内存(创建字符串后):5036040

Below is the code snippet to examine the memory

public class TestFreeMemory {

    public static void main(String ... args){

        Runtime rt = Runtime.getRuntime();
        System.out.println("Free Memory (Before GC): " + rt.freeMemory());

        rt.gc();
        System.out.println("Free Memory (After GC1): " + rt.freeMemory());

        rt.gc(); // Second time to ensure results are consistent 
                 // MAY BE has collected all non-reachable objects
        System.out.println("Free Memory (After GC2): " + rt.freeMemory());

        String s = new String("abcd");
        Integer i = new Integer(12345);
        System.out.println("Free Memory (After String Creation): " + rt.freeMemory());
        // Why is freeMemory not reflecting the memory consumed by two objects
    }

}

and the output is

Free Memory (Before GC): 1859672
Free Memory (After GC1): 1911768
Free Memory (After GC2): 1911768
Free Memory (After String Creation): 1911768

Why is freeMemory not reflecting the memory consumed by two objects ?


To be more clear, the question is about getMemory() call not showing up expected result even though two objects are created and not related to GC. Two GC calls are made just to try to make sure the numbers of getMemory() call are correct.. and BTW, there's no GC call after objects are created.. so pls Note that i am not trying for a GC after objects are created ..

解决方案

Memory Management on HotSpot JVM:

Another desirable garbage collector characteristic is the limitation of fragmentation. When the memory for garbage objects is freed, the free space may appear in small chunks in various areas such that there might not be enough space in any one contiguous area to be used for allocation of a large object. One approach to eliminating fragmentation is called compaction, discussed among the various garbage collector design choices below.

Memory Management in HotSpot JVM (PDF Format).

This behavior can be very dependent on the particular implementation of the garbage collection. For example:

Parallel Mark Compact

  • Stop-the-world
  • Heap divided into fixed-size chunks (> 2kb now, will likely increase or be subject to ergonomics)
  • Chunk is unit of live data summarization
  • Parallel mark
  • Record live data addresses in external bitmap
  • Find per chunk live data size
  • Find dense chunks, i.e., ones that are (almost) full of live objects


I've made this sample (with abusive String concatenation to use up more memory):

public class TestFreeMemory {

 static void allocateSomeMemory(){
  long[][] array = new long[400][400];
 }

    public static void main(String ... args){

        Runtime rt = Runtime.getRuntime();

        allocateSomeMemory(); // once we leave, our array is not reachable anymore 
        System.out.println("Free Memory (Before GC): " + rt.freeMemory());     
        rt.gc();
        System.out.println("Free Memory (After GC): " + rt.freeMemory());

        String a = new String("A");
        for(int i = 0; i < 100; i++){
         a+="B";
        }

        System.out.println("Free Memory (After String Creation): " + rt.freeMemory());
        // Less free memory expected.
    }

}

Output:

Free Memory (Before GC): 3751800

Free Memory (After GC): 5036104

Free Memory (After String Creation): 5012048


If I use a relatively small number of iterations in the loop (say 10), the extra space does not show up in freeMemory(), and I'd get something like this:

Free Memory (Before GC): 3751800

Free Memory (After GC): 5036040

Free Memory (After String Creation): 5036040

这篇关于运行时 - 为什么 freeMemory() 没有正确显示内存消耗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆