【问题标题】:Unexpected Result from using getRuntime().freeMemory()使用 getRuntime().freeMemory() 的意外结果
【发布时间】:2020-06-26 11:17:59
【问题描述】:

我打算使用getRuntime().freeMemory() 粗略估计java 方法消耗了多少内存。我试图通过以下方式实现它:

long beforeUsedMem=Runtime.getRuntime().totalMemory()-Runtime.getRuntime().freeMemory();
foo();
long afterUsedMem=Runtime.getRuntime().totalMemory()-Runtime.getRuntime().freeMemory();
long actualMemUsed=afterUsedMem-beforeUsedMem;

为了测试这是否真的可行,我运行了下面的代码

long beforeUsedMem=Runtime.getRuntime().totalMemory()-Runtime.getRuntime().freeMemory();
List<Integer> list = new ArrayList<>();
for(int i = 0 ;i<1000;i++)
  list.add(i);

long afterUsedMem=Runtime.getRuntime().totalMemory()-Runtime.getRuntime().freeMemory();
long actualMemUsed=afterUsedMem-beforeUsedMem;
System.out.println("mem used "+actualMemUsed);

但是,程序的输出结果是

mem used 0

但是,如果我从 0 -> 100000 循环,输出结果是

mem used 2684368

谁能解释一下为什么 jvm 会这样工作?

【问题讨论】:

  • Total 和 free 相等,所以结果为 0。然后你使用了一些内存,所以值不再是 0?
  • @MissingSemiColon 为什么我添加到列表后可用内存相同?
  • 总内存 = 10.000.000,可用内存 = 10.000.000 使用内存后:总内存 = 10.000.000,可用内存 = 8.000.000 stackoverflow.com/questions/3571203/…。不能说我也不希望它为 0,但这是我能想到的唯一合乎逻辑的解释。
  • 垃圾收集可以在任何时间点进行。此外,在代码执行开始时,可​​能已经存在任意数量的可回收垃圾。因此,差异是任意且毫无意义的。这个数字甚至可以是负数,例如当预先存在的垃圾占用的内存比代码中分配的对象多时。

标签: java memory jvm


【解决方案1】:

问题是getRuntime().freeMemory() 没有做你认为它正在做的事情。

JVM 将根据需要以块的形式分配内存,并且根据您使用的 GC,可能还会将内存返回给操作系统。因此,您从内存选项中看到的结果取决于 JVM 正在执行的操作,而不是单个方法执行的操作。

如果您想测量由 Java 方法分配的对象数量,您应该查看 JMH,特别是 GC 分析器。这将重复运行您的方法,然后根据垃圾收集运行 JMX 收集的信息取平均值。

我写了一个blog post 使用 JMH 和 prof gc 的 StringBuilder 的性能。 GitHub 上的source is available 供参考。

TL;DR 是你想要类似的东西:

@State(Scope.Benchmark)
public class StringBuilderBenchmark {
    
    @Benchmark
    public String testEmptyBuffer() {
        StringBuffer buffer = new StringBuffer();
        return buffer.toString();
    }
}

然后您使用 mvn jmh arhectype 使用 JMH 编译/构建它并使用 prof gc 运行它:

java -jar target/benchmarks.jar \
   -wi 5 -tu ns -f 1 -bm avgt -prof gc

然后它将重复运行该方法,并为您提供每次调用您的方法时分配的平均字节数。

请注意,它不会测量所需的一次性初始化;例如,如果你懒惰地分配了一个包含一百万个条目的巨型 Map,它不会被这个过程计算在内。

有关 JMH 的更多信息,请访问on the JMH homepage

【讨论】:

    猜你喜欢
    • 2021-12-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多