Java中的JVM虚拟机的内存与直接内存
一. 定义
直接内存不属于java虚拟机内存,而属于操作系统内存
当我调用直接内存(Direct Memory)
Direct Memory 常见于 NIO 操作时,用于数据缓冲区 分配回收成本较高,但读写性能高 不受 JVM 内存回收管理
二. 直接内存的内存溢出
-
演示图: 演示代码:
package jvm1; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; public class Demo9 { static int _100Mb = 1024 * 1024 * 100; public static void main(String[] args) { List<ByteBuffer> list = new ArrayList<>();//加入声明周期更长的List集合中 int i = 0; try { while (true) { ByteBuffer byteBuffer = ByteBuffer.allocateDirect(_100Mb); list.add(byteBuffer); i++; } } finally { System.out.println(i); } // 方法区是jvm规范, jdk6 中对方法区的实现称为永久代 // jdk8 对方法区的实现称为元空间 } }
三. 直接内存的释放原理
案例1
分析1 分析2
-
源码分析: 垃圾回收GC分析:
-XX:+DisableExplicitGC 禁用显式的垃圾回收
-
原代码:
package jvm1; import java.io.IOException; import java.nio.ByteBuffer; /* 禁用显式回收对直接内存的影响 */ public class Demo10 { static int _1Gb = 1024 * 1024 * 1024; /* * -XX:+DisableExplicitGC 显式的 */ public static void main(String[] args) throws IOException { ByteBuffer byteBuffer = ByteBuffer.allocateDirect(_1Gb); System.out.println("分配完毕..."); System.in.read();//回车键 System.out.println("开始释放..."); byteBuffer = null; System.gc(); // 显式的垃圾回收,Full GC System.in.read(); } }
案例2:
分析1
-
原代码:
package jvm1; import sun.misc.Unsafe; import java.io.IOException; import java.lang.reflect.Field; /* 直接内存分配的底层原理:Unsafe */ public class Demo11 { static int _1Gb = 1024 * 1024 * 1024; public static void main(String[] args) throws IOException { Unsafe unsafe = getUnsafe(); // 分配内存 long base = unsafe.allocateMemory(_1Gb); unsafe.setMemory(base, _1Gb, (byte) 0); System.in.read(); // 释放内存 unsafe.freeMemory(base); System.in.read(); } public static Unsafe getUnsafe() { try { Field f = Unsafe.class.getDeclaredField("theUnsafe"); f.setAccessible(true); Unsafe unsafe = (Unsafe) f.get(null); return unsafe; } catch (NoSuchFieldException | IllegalAccessException e) { throw new RuntimeException(e); } } }
根据案例1和案例2的总结:
-
分配和回收原理 使用了 Unsafe 对象完成直接内存的分配回收,并且回收需要主动调用 freeMemory 方法 ByteBuffer 的实现类内部,使用了 Cleaner (虚引用)来监测 ByteBuffer 对象,一旦ByteBuffer 对象被垃圾回收,那么就会由 ReferenceHandler 线程通过 Cleaner 的 clean 方法调用 freeMemory 来释放直接内存
下一篇:
python和java哪个更值得学?