这是我参与11月更文挑战的第13天,活动详情查看:2021最后一次更文挑战」
内存溢出
虽然直接内存(Direct Memory)不受jvm管理,但是它还是会有内存溢出的情况。
示例
1 | js复制代码 static int ONE_HUNDRED_GB = 1024 * 1024 * 1024; |
运行上面这段代码会报出:java.lang.OutOfMemoryError: Direct buffer memory 错误,提示直接内存溢出。
这里运行了三次就报直接内存溢出
运行前本机内存
运行时本机内存
总结
虽然直接内存并不由我们的jvm进行分配管理,但是还是会出现内存溢出的情况。
通过运行前内存和运行时内存可以看出,直接内存并不会占满我们计算机系统的所有内存,当达到一定大小时就会抛出内存溢出信息。
释放原理
直接内存的分配和回收释放主要是用到了一个叫做Unsafe对象。
分配是使用该对象中提供的本地方法 allocateMemory() 方法,在Java程序中最终是通过调用 Unsafe 对象中allocateMemory() 进行直接内存的分配。
回收释放是使用该对象中提供 freeMemory() 的本地方法进行直接内存的回收释放。
主要的体现在 ByteBuffer.allocateDirect 源码中,先点进该源码中。
再进入 new DirectByteBuffer(capacity) 方法中查看该源码。
在这里就能看到是通过 unsafe.allocateMemory(size) 方法进行分配的直接内存,然后们再看具体实现?进入会发现这个方法是 native 的,该方法的实现由其它的语言进行实现的没法查看,但是我们知道直接内存最终是通过该方法分配的就行。
我们继续找直接内存的释放,这段代码不能直接看到释放的方法,我们进入 new Deallocator(base, size, cap) 这里面,然后会发现下面有个run() 方法,该方法中调用了直接内存释放的方法 unsafe.freeMemory(address);
那么到底是怎么执行该 run() 方法的,看前面那张图主要是通过 cleaner(虚引用类型)它的特点是:当它所关联的这个对象被jvm回收时就会触发 Cleaner.clean 方法。
这里它关联的是ByteBuffer 对象,该对象是java对象,当该对象被垃圾回收掉时它就会执行 Cleaner 对象中 clean 方法。
查看 Cleaner 对象中clean方法
在这里会调用到刚才的 run() 方法进行直接内存的回收释放。
本文转载自: 掘金