如何确定直接内存的大小
一般情况下,当我们明确需要使用直接内存的话,我们就会自己批定最大内存的大小,可以通过 -XX:MaxDirectMemorySize 参数来进行指定。当然通过Unsafe类来操作直接内存时,那么它是不会受这个参数的限制。比如ByteBuffer是受这个参数的限制。
那么问题是,如果我们不通过 -XX:MaxDirectMemorySize 参数来指定最大直接内存的情况下,默认的直接内存是多大呢?接下来就通过一些案例测试一下。
案例
这里准备一个简单的案例,如下图
(1)手动指定直接内存的大小
指定直接内存大小。参数为 -XX:MaxDirectMemorySize=100m
运行代码后,结果如下
指定直接内存大小。参数为 -XX:MaxDirectMemorySize=128m
运行代码后,结果如下
(2)不手动指定直接内存的大小,但指定堆的大小
运行代码后,结果如下
明明最大内存和代码里要求的是一样的大小,都是128M,为什么还是分配不下呢?
再改动堆的大小,如图
运行代码,结果如下
明明最大内存已经大于128M,为什么还是分配不下呢?
再改动堆的大小,如图
运行代码,结果如下
看到这里,是不是很奇怪,为什么把最大的堆内存再调大一点,就可以分配下128M的直接内存呢?
总结
通过这个案例分析, 我们得出以下结论:
在没有显示的设置-XX:MaxDirectMemorySize 参数,通过 ByteBuffer 能够分配的直接内存空间大小就是堆的最大的可使用的大小。堆的最大的可使用的大小= 堆的最大值- 一个 Survivor 的大小(浪费的空间)
所以就不难理解,把堆的最大值调整为135M时,为什么会 OOM,因为堆的最大的可使用的大小=135-10m=125m ,不能分配 128M 的对象;而调整为138M时,堆的最大的可使用的大小=138-10m=128m ,刚好可以分配 128M 的对象