堆外内存

@[toc] --- ## 堆外内存的优缺点 Java 中的对象都是在 JVM 堆中分配的,其好处在于开发者不用关心对象的回收。但有利必有弊,堆内内存主要有两个缺点 1. GC 是有成本的,堆中的对象数量越多,GC 的开销也会越大 2. 使用堆内内存进行文件、网络的 IO 时,JVM 会使用堆外内存做一次额外的中转,也就是会多一次内存拷贝 和堆内内存相对应,**堆外内存就是把内存对象分配在 Java 虚拟机堆以外的内存,这些内存直接受操作系统管理(而不是虚拟机)**,这样做的好处就是: 1. 能够在一定程度上减少垃圾回收对应用程序造成的影响 2. 加快了复制的速度:堆内在 flush 到远程时,会先复制到直接内存(非堆内存),然后在发送;而堆外内存相当于省略掉了这个工作 堆外内存的缺点就是内存难以控制,使用了堆外内存就相当于失去了 JVM 管理内存的可行性,改由自己来管理,当发生内存溢出时排查起来非常困难 ## 堆外内存的使用场景 - **适合长期存在或能复用的场景**:堆外内存分配回收也是有开销的,所以适合长期存在的对象 - **适合注重稳定的场景**:堆外内存能有效避免因 GC 导致的 STW 问题 - **适合简单对象的存储**:因为堆外内存只能存储字节数组,所以对于复杂的DTO对象,每次存储/读取都需要序列化/反序列化 - **适合注重IO效率的场景**:用堆外内存读写文件性能更好 ## Java 堆外内存的实现 Java 中分配堆外内存的方式有两种,一是通过 `ByteBuffer.java#allocateDirect` 得到以一个 `DirectByteBuffer` 对象,二是直接调用 `Unsafe.java#allocateMemory` 分配内存,但Unsafe只能在JDK的代码中调用,一般不会直接使用该方法分配内存。 其中 DirectByteBuffer 也是用 Unsafe 去实现内存分配的,对堆内存的分配、读写、回收都做了封装