关于 java 中的可用内存问题

最近看了《why 技术》的一篇文章《这个队列的思路是真的好,现在它是我简历上的亮点了。》。本来没什么问题,觉得这么好的东西不拿来用一用太可惜了。于是我就搞到了项目中,但是却发现一个问题,文中提到的:

1
2
MemoryUsage heapMemoryUsage = MX_BEAN.getHeapMemoryUsage();
long availableMemory = heapMemoryUsage.getCommitted();

我发现availableMemory在一段时间内没什么变化。

我是这么测试的:

1
2
3
4
5
6
7
8
9
10
public static void main(String[] args) throws InterruptedException {
List<byte[]> objects = new ArrayList<>();
long _1MB = 1024 * 1024;
while (true) {
MemoryUsage heapMemoryUsage = MX_BEAN.getHeapMemoryUsage();
System.out.println("committed:"+heapMemoryUsage.getCommitted()/_1MB);
objects.add(new byte[1024 * 1024 * 50]);
Thread.sleep(100L);
}
}

讲道理应该实时变化才对,后来我点进去了why哥留下的PR链接,发现这个PR在2022-06-06有一个提交:
1
备注信息为:”fix bug”,具体的修改为:
2
可以看到原来通过MemoryUsage获取可用内存变成了:

1
Runtime.getRuntime().freeMemory()

也就是说之前使用的getCommited()获取的并不是可用内存,于是我看了下MemoryUsage的源码(jdk8),哈哈哈😂,发现图示的很清楚:
3
真正的可用空间是committed - used,于是我又做了下面的测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
public static void main(String[] args) throws InterruptedException {
List<byte[]> objects = new ArrayList<>();
long _1MB = 1024 * 1024;
while (true) {
MemoryUsage heapMemoryUsage = MX_BEAN.getHeapMemoryUsage();
long freeMemory = Runtime.getRuntime().freeMemory();
System.out.println("freeMemory:"+freeMemory/_1MB);
System.out.println("committed:"+heapMemoryUsage.getCommitted()/_1MB);
System.out.println("committed - used:"+(heapMemoryUsage.getCommitted()-heapMemoryUsage.getUsed())/_1MB);
objects.add(new byte[1024 * 1024 * 50]);
Thread.sleep(100L);
}
}

4

可以看到确实如此。


20220615更新

why哥给我回复了,这个问题大佬也讨论过https://github.com/apache/dubbo/pull/10021#issuecomment-1147464751

其中一个大佬说的可用内存应该是:

1
MemoryUsage#getMax() - MemoryUsage#getUsed()

然后我在 github 上回复了一下大佬,大佬给我的答复是:
5