【问题标题】:Java: on the cost of calling Runtime.freeMemory(), Runtime.totalMemory() and Runtime.maxMemory()Java:关于调用 Runtime.freeMemory()、Runtime.totalMemory() 和 Runtime.maxMemory() 的成本
【发布时间】:2012-01-21 08:25:45
【问题描述】:

我在内存中有一个Map 来存储我的对象。当我用完内存时,我想刷新到内存。我现在正在这样做:

void add(K key, V value) {
    if (underPressure()) {
        flush(innerMap);
    }
    innerMap.add(k, v);
}

boolean underPressure() {
    Runtime rt = Runtime.getRuntime();
    long maxMemory = rt.maxMemory();
    long freeMemory = rt.freeMemory();

    return (double) freeMemory / maxMemory < threshold;
}

由于每次插入时都会调用underPressure(),所以它有多贵?据我了解,由于它是一个近似值,它应该由 jvm 以某种方式缓存,但是有人真正了解这一点吗?

【问题讨论】:

  • 它可能在不同的机器上有所不同。在你的机器上有多贵?您还可以测试return freememory &lt; maxMemory * threshold;,因为乘法比除法稍快。
  • 注意:freeMemory 只告诉你在需要执行 GC 之前你有多少内存。它不会告诉你 GC 后有多少是免费的。
  • 就我个人而言,我会去final boolean underPressure() 或者有人会继承并使用带有非常糟糕歌词的说唱来覆盖该方法。然后,每当有人看到该方法签名时,如果他们未超过一定年龄,他们就会将其识别为 Vanilla Ice 的版本,而您将一头雾水。 :-(
  • 在我的电脑上平均需要 72 ns。
  • 是的,在我的机器上它比new ArrayList&lt;String&gt;()慢了大约 50 倍

标签: java performance memory garbage-collection jvm


【解决方案1】:

不直接回答您的问题,但正如 cmets freeMemory 中已经说过的那样,计算空闲内存而不是 GC 后可用的内存,因此如果您调用 freeMemory 在 GC 运行之前,您可能认为您已达到“underPressure”限制,但您也可以在下一次 GC 运行后拥有大量可用内存。

另一种方法可能是创建一个软可达对象并检查它是否被 GC 声明:

类似:

SoftReference<Object> sr = new SoftReference<Object>(new Object(),new ReferenceQueue<Object>());
public boolean underPressure(){
    if (sr.isEnqueued()) {
        // recreate object to monitor
        sr = new SoftReference<Object>(new Object(),new ReferenceQueue<Object>());
        return true;
    }
    return false;
}

【讨论】:

  • 问题:为什么要使用 ReferenceQueue? sr.get() == null 是否足以检查是否有压力(并且在这种情况下也重新创建 sr)?
【解决方案2】:

为什么不使用JMXBeans 来执行此操作。它旨在简化此类操作..

来自文档...

API 提供对以下信息的访问:

Number of classes loaded and threads running
Virtual machine uptime, system properties, and JVM input arguments
Thread state, thread contention statistics, and stack trace of live threads
Memory consumption
Garbage collection statistics
Low memory detection
On-demand deadlock detection
Operating system information

具体见MemoryPoolMXBean中的示例代码

【讨论】:

  • 听起来是正确的地方。谢谢你的建议。
【解决方案3】:

从 Java 7 开始,不再需要轮询空闲内存。可以注册垃圾收集事件。看到这个帖子:http://www.fasterj.com/articles/gcnotifs.shtml

所以我能想到的最好方法是在垃圾回收后检查可用内存,然后在需要时释放额外空间。

【讨论】:

    猜你喜欢
    • 2022-09-23
    • 2011-07-30
    • 2010-11-30
    • 1970-01-01
    • 1970-01-01
    • 2014-07-05
    • 1970-01-01
    • 2016-11-06
    相关资源
    最近更新 更多