Java:关于调用Runtime.freeMemory(),Runtime.totalMemory()和Runtime.maxMemory()的成本

9

我在内存中有一个存储对象的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 进行 缓存,但有人对此了解更多吗?


1
它可能在不同的机器上有所不同。在你的机器上需要多少资源?你也可以测试 return freememory < maxMemory * threshold;,因为乘法比除法稍微快一些。 - Peter Lawrey
2
个人而言,我会选择 final boolean underPressure(),否则有人会用一首非常糟糕的说唱歌曲来覆盖这个方法。那么每当有人看到这个方法签名时,如果他们还没有超过某个年龄,他们就会将其与 Vanilla Ice 的版本联系起来,你就会失败了。 :-( - corsiKa
4
在我的电脑上,平均需要72纳秒。 - Peter Lawrey
是的,在我的电脑上,它比“new ArrayList<String>()”慢大约50倍。 - marcorossi
如果您使用弱键和WeakHashMap,垃圾回收不是应该为您完成这项工作吗? - mazaneicha
显示剩余4条评论
3个回答

5
自从Java 7以来,不再需要轮询可用内存。可以注册垃圾回收事件。请参见此帖子:http://www.fasterj.com/articles/gcnotifs.shtml 因此,我认为最好的方法是在垃圾回收后检查可用内存,然后释放额外的空间,如果需要的话。

3
为什么不使用JMXBeans来完成这个任务。它旨在简化这种操作。
从文档中得知...

The API provides access to information such as:

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中的示例代码。


Translated:

Specifically see the example code in MemoryPoolMXBean


听起来是一个正确的查看位置。感谢您的建议。 - marcorossi

2

虽然不是直接回答您的问题,但正如评论中已经说过的那样,freeMemory计算的是可用内存而不是在GC运行后可用的内存,因此如果您在GC运行之前调用freeMemory,您可能会认为已经达到了"承压"限制,但在下一次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)不足够吗? - marcorossi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接