使用Runtime.getRuntime()。totalMemory()和freeMemory()来计算内存时会产生混淆的结果?

时间:2015-12-18 02:28:00

标签: java memory

我使用Runtime.getRuntime().totalMemory()freeMemory()来计算内存。但是,我对结果感到困惑。

我已经阅读过帖子:

What are Runtime.getRuntime().totalMemory() and freeMemory()?

a question on Runtime.getRuntime().totalMemory()

这是我的演示代码:

package test;

class Memory

{

public static long used()

{

long total=Runtime.getRuntime().totalMemory();

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

return (total-free);

}

}



package test;

import java.util.ArrayList;

public class MemTestQuestion {

    private static final long _10M = 10000000;

    public static void main(String[] args) {

        int runCount=10;
        for (int i = 0; i < runCount; i++) {
            arrayListMemTest();
        }
    }

    public static void arrayListMemTest()
    {
        long startTime = System.currentTimeMillis();
        long startMem=Memory.used();

        ArrayList<Integer>al= new ArrayList<Integer>();
        for (int i = 0; i < _10M; i++) {
            al.add(1000);
        }

        long endMem= Memory.used();
        long endEndTime = System.currentTimeMillis();

        long timeLast = endEndTime - startTime;
        long memUsed = endMem-startMem;


        System.out.print("lasts:"
                + timeLast + "ms = "+timeLast/1000.0+"s\t");
        System.out.println("mem used:"
                +memUsed+"bytes = "+new java.text.DecimalFormat("#.00").format(memUsed/(1024*1024.0))+"M");

        System.gc();
    }

}

以下是runCount = 1(位于Main方法中的变量)的结果:

lasts:3606ms = 3.606s   mem used:214644488bytes = 204.70M

以下是runCount = 10时的结果:

lasts:3643ms = 3.643s   mem used:214644488bytes = 204.70M
lasts:389ms = 0.389s    mem used:254054928bytes = 242.29M
lasts:366ms = 0.366s    mem used:219163424bytes = 209.01M
lasts:242ms = 0.242s    mem used:256265992bytes = 244.39M
lasts:222ms = 0.222s    mem used:255523768bytes = 243.69M
lasts:225ms = 0.225s    mem used:253843192bytes = 242.08M
lasts:253ms = 0.253s    mem used:253967736bytes = 242.20M
lasts:236ms = 0.236s    mem used:253994680bytes = 242.23M
lasts:234ms = 0.234s    mem used:254066232bytes = 242.30M
lasts:233ms = 0.233s    mem used:254091448bytes = 242.32M

让我最困惑的是,当runCount=10时,最多的结果是大约240M。但是当runCount=1时,结果大约是200M。

我想这是因为JAVA JVM没有及时收集垃圾,所以第一个结果更有说服力。 我是对的吗?如果没有,有人可以提供一些线索或其他建议吗?提前致谢。

演示代码的目的是尝试比较标准的java容器和第三方的容器。

2 个答案:

答案 0 :(得分:3)

  

我想这是因为JAVA JVM没有及时收集垃圾,所以第一个结果更有说服力。我对吗?

我不这么认为。运行System.gc()应该是一个提示“尽最大努力”收集所有垃圾的提示。马上。提示可以忽略,但如果GC确实运行,您可以期望它执行&gt;&gt;完整&lt;&lt;收集,只有在完成后才返回。 GC不应该“跟上”。

  

如果没有,有人可以提供一些线索或其他建议吗?

这可能是由于JIT编译和其他JVM预热效果。

当您的应用程序启动时,您的代码的方法和所有使用的(传递)库方法都是字节码,并将由字节码解释器解释。在解释字节码时,JVM会收集各种事物的统计信息(例如,协助分支预测)。最终,它决定JIT编译方法。

那么这与你的观察有什么关系?

  1. 统计信息存储在堆中,并且可以访问...直到JIT编译器“消耗”它们。

  2. JIT编译器异步运行,当它运行时,它也将使用堆空间来保存其数据结构。

  3. 在启动时,JVM必须加载类,这也会占用堆空间来保存临时对象。

  4. 堆大小不是常量。它会增长(有时缩小),具体取决于每个GC循环后可用空间的大小。

  5. 在JVM预热阶段,所有这些结合起来在堆大小和堆空间使用方面给出了本地“高点”和“低点”。

答案 1 :(得分:2)

我按照以下方式创建set_source_files_properties(${td_file} PROPERTIES GENERATED true) ..

ArrayList

运行代码之后,我意识到你的混乱结果并没有发生,因为 ArrayList<Integer> al = new ArrayList<Integer>(){ @Override protected void finalize() throws Throwable { super.finalize(); System.out.println("finalize"); } }; 没有收集垃圾。上述代码的结果如下:

  

持续时间:4875ms =使用4.875s内存:250675056bytes = 239.06M
  持续时间:437ms = 0.437s内存使用:278614888bytes = 265.71M
  完成
  完成
  持续时间:594ms = 0.594s内存使用:252543848bytes = 240.84M
  完成
  持续时间:266ms = 0.266s内存使用:277680536bytes = 264.82M
  完成
  持续时间:312ms = 0.312s内存使用:280390568bytes = 267.40M
  完成
  持续时间:297ms = 0.297s内存使用:278106248bytes = 265.22M
  完成
  持续时间:297ms = 0.297s内存使用:277852312bytes = 264.98M
  完成
  持续时间:312ms = 0.312s内存使用:277885640bytes = 265.01M
  完成
  持续时间:297ms = 0.297s内存使用:277897448bytes = 265.02M
  完成
  持续时间:312ms = 0.312s内存使用:277899896bytes = 265.03M
  敲定

在此代码中,第一次运行时,它显示的值(JVM)小于平均值。

然后我更改了239.06M

main method

结果是:

  

持续时间:2640ms = 2.64s使用的mem:275635104bytes = 262.87M
  持续时间:624ms = 0.624s内存使用:253167968bytes = 241.44M
  完成
  完成
  持续时间:411ms = 0.411s内存使用:303362328bytes = 289.31M
  完成
  持续时间:527ms = 0.527s内存使用:253055288bytes = 241.33M
  完成
  持续时间:329ms = 0.329s内存使用:280855512bytes = 267.84M
  完成
  持续时间:340ms = 0.34s内存使用:252478904bytes = 240.78M
  完成
  持续时间:350ms = 0.35s内存使用:277791960bytes = 264.92M
  完成
  持续时间:312ms = 0.312s内存使用:277059280bytes = 264.22M
  完成
  持续时间:314ms = 0.314s内存使用:279330968bytes = 266.39M
  完成
  持续时间:376ms = 0.376s内存使用:278511960bytes = 265.61M
  敲定

这一次,它显示了public static void main(String[] args) throws InterruptedException { Thread.sleep(7000); int runCount = 10; for (int i = 0; i < runCount; i++) { arrayListMemTest(); } } 附近的平均值。

我认为,260M需要一些时间来完全加载其库。程序在完全初始化JVM之前运行。