01 直接内存(Direct Memory)
线程共享
并不是虚拟机运行时数据区的一部分,jdk7和jdk8都有
JDK 1.4新加入了NIO(New Input/Output)类,引入了一种基于通道(Channel)与缓冲区(Buffer)的I/O方式,可以使用Native函数库直接分配堆外内存(直接内存),然后通过一个存储在Java堆里面的DirectByteBuwffer对象作为这块内存的引用进行操作。 这样能在一些场景中显著提高性能,避免了在Java堆和Native堆中来回复制数据
NIO的Buffer提供一个可以直接访问系统物理内存的类——DirectBuwffer。DirectBuwffer类继承自ByteBuffer,和普通的ByteBuffer不同。普通的ByteBuffer仍在JVM堆上分配内存,其最大内存受到最大堆内存的限制。而DirectBuffer直接分配在物理内存中,并不占用堆空间。在访问普通的ByteBuffer时,系统总是会使用一个“内核缓冲区”进行操作。而DirectBuffer所处的位置,相当于这个“内核缓冲区”。因此,使用DirectBuffer是一种更加接近内存底层的方法,所以它的速度比普通的ByteBuffer更快
通过使用堆外内存,可以带来以下好处:
- 改善堆过大时垃圾回收效率,减少停顿。Full GC时会扫描堆内存,回收效率和堆大小成正比。Native的内存,由OS负责管理和回收
- 减少内存在Native堆和JVM堆拷贝过程,避免拷贝损耗,降低内存使用
- 可突破JVM内存大小限制
不是虚拟机运行时数据区的一部分,也不是《Java虚拟机规范》中定义的内存区域
直接内存是在Java堆外的、直接向系统申请的内存区间
来源于NIO,通过存在堆中的DirectByteBuffer操作Native内存通常,访问直接内存的速度会优于Java堆。即读写性能高。出于性能考虑,读写频繁的场合可能会考虑使用直接内存
java的NIO库允许Java程序使用直接内存,用于数据缓冲区
也可能导致OutOfMemoryError常由于直接内存在Java堆外,因此它的大小不会直接受限于-xmx指定的最大堆大小,但是系统内存是有限的,Java堆和直接内存的总和依然受限于操作系统能给出的最大内存
缺点
分配回收成本较高
不受JVM内存回收管理
直接内存大小可以通过MaxDirectMemorysize设置如果不指定,默认与堆的最大值-Xn
02 直接内存溢出
直接内存(Direct Memory)容量大小可通过-XX: MaxDirectMemorySize参数来指定, 如果不去指定, 则默认与Java堆最大值(由-Xmx指定)一致, 越过了DirectByteBuer类直接通过反射获取Unsafe实例进行内存分配
(Unsafe类的getUnsafe()方法指定只有引导类加载器才会返回实例, 体现了设计者希望只有虚拟机标准类库里面的类才能使用Unsafe的功能, 在JDK 10时才将Unsafe 的部分功能通过VarHandle开放给外部使用), 因为虽然使用DirectByteBuer分配内存也会抛出内存溢出异常, 但它抛出异常时并没有真正向操作系统申请分配内存, 而是通过计算得知内存无法分配就会 在代码里手动抛出溢出异常, 真正申请分配内存的方法是Unsafe::allocateMemory()
public class DirectMemoryOOM {
private static final int _1MB = 1024 * 1024;
public static void main(String[] args) throws Exception {
Field unsafeField = Unsafe.class.getDeclaredFields()[0];
unsafeField.setAccessible(true);
Unsafe unsafe = (Unsafe) unsafeField.get(null);
while (true) {
unsafe.allocateMemory(_1MB);
}
}
}
运行结果
Exception in thread “main” java.lang.OutOfMemoryError
at sun.misc.Unsafe.allocateMemory(Native Method)
at DirectMemoryOOM.main(DirectMemoryOOM.java:12)
由直接内存导致的内存溢出, 一个明显的特征是在Heap Dump文件中不会看见有什么明显的异常情况, 如果发现内存溢出后产生的Dump文件很小, 而程序中又直接或间接使用了DirectMemory(典型的间接使用就是NIO),那就可以考虑重点检查一下直接内存方面的原因了。