运行时 - 为什么freeMemory()没有正确显示内存消耗?

时间:2010-08-06 07:42:43

标签: java runtime

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

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
    }

}

,输出

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

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


更清楚的是,问题是getMemory()调用没有显示预期结果,即使创建了两个对象并且与GC无关。两个GC调用只是为了确保getMemory()调用的数量是正确的..而且BTW,在创建对象后没有GC调用..所以请注意我在创建对象后没有尝试GC ..

4 个答案:

答案 0 :(得分:3)

HotSpot JVM上的内存管理:

  

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

Memory Management in HotSpot JVM (PDF Format).

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

  

Parallel Mark Compact

     
      
  • 停止的环球
  •   
  • 堆分为固定大小的块(现在大约2kb,可能会增加或者是   受人体工程学影响)
  •   
  • Chunk是实时数据汇总的单位
  •   
  • 平行标记
  •   
  • 在外部位图中记录实时数据地址
  •   
  • 查找每个块实时数据大小
  •   
  • 找到密集的块,即(几乎)充满活动对象的块
  •   

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

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.
    }

}

<强>输出

  

可用内存(GC之前):3751800

     

可用内存(GC后):5036104

     

可用内存(字符串创建后):   5012048


如果我在循环中使用相对较少的迭代次数(例如10),额外空间不会出现在freeMemory()中,我会得到类似的结果:

  

可用内存(GC之前):3751800

     

可用内存(GC后):5036040

     

可用内存(字符串创建后):   5036040

答案 1 :(得分:1)

这是一个很好的问题,因为您希望反映内存使用量的增加,这似乎是一个逻辑测试。您可以假设这种行为是因为堆管理和垃圾收集系统比简单的Free vs Allocated边界稍微复杂一些。分配可能是在比你的一个String +一个整数大得多的块中完成的,所以可以通过总结空闲块来计算空闲内存。

答案 2 :(得分:0)

调用GC时,GC不释放内存,但需要更多内存时。

答案 3 :(得分:0)

尝试分配更多内存,您会看到增加。我想java预分配至少足够的字节(多么聪明!)来保存你的字符串或者它们已经在字符串池中了。