定义:操作系统内存,常见于NIO操作时,用于数据缓冲区,分配回收成本较高,但读写性能高,不受JVM内存回收管理
用以下代码来演示ByteBuffer和IO读写性能差别:
public class Demo_9 { static final String From="C:\Test_buff\学习雷锋.qlv"; static final String To="D:\学习雷锋.qlv"; static final int _1MB=1024*1024; public static void main(String[] args) { io(); directBuffer(); } private static void directBuffer(){ long start=System.nanoTime(); try(FileChannel from=new FileInputStream(From).getChannel(); FileChannel to=new FileOutputStream(To).getChannel(); ){ ByteBuffer bb=ByteBuffer.allocateDirect(_1MB);//在系统内存和java堆内存划分出一块共用区域(direct memory) while (true){ int len=from.read(bb); if(len==-1){ break; } bb.flip(); to.write(bb); bb.clear(); } } catch (IOException e){ e.printStackTrace(); } long end=System.nanoTime(); System.out.println("directBuffer用时:"+(end-start)/1000_000.0); } private static void io(){ long start=System.nanoTime(); try(FileInputStream from=new FileInputStream(From); FileOutputStream to=new FileOutputStream(To); ){ byte[] buf = new byte[_1MB]; while (true){ int len=from.read(buf); if(len==-1){ break; } to.write(buf,0,len); } } catch (IOException e){ e.printStackTrace(); } long end=System.nanoTime(); System.out.println("io用时:"+(end-start)/1000_000.0); }}
运行结果如下:
这里演示用的文件比较小,文件大一点,差别就可以很明显的体现处来
为什么使用Bytebuffer后,大文件的读写效率变高?
IO文件读写过程如图:
因为经过了两个缓存区(java缓存区和系统缓存区),所以造成不必要的数据复制
使用直接缓存区的过程如下图:
直接内存溢出在java中所报的错误信息:java.lang.OutOfMemoryError: Direct buffer memory
用以下代码进行测试(jdk版本1.8)
public class Demo_10 { static int _100MB=1024*1024*100; public static void main(String[] args) { List
直接内存释放原理:Unsafe类(非常底层类,不建议使用)分配直接内存:
long base=unsafe.allocateMemory();//返回分配直接内存的地址unsafe.setMemory(base,_1GB,(byte,0));//_1GB表示大小为1GB的快捷
释放直接内存
unsafe.freeMemory(base);
通过上面的代码验证直接内存的分配和释放是通过unsafe,而不是垃圾回收
直接内存的释放是借助的虚引用对象(Cleaner),特点是:当关联的对象(DirectByteBuffer)被回收时,会触发虚引用的clean方法,当ByteBuffer对象被垃圾回收后,会触发Cleaner的clean方法,然后执行任务对象,再调用unsafe.freeMemory();
在JVM调优时,经常会加一条参数:-XX:+DisableExplicitGC,意义是禁用显示的垃圾回收,就是让代码中的System.gc()无效,因为System.gc()触发的是一次Full GC,比较影响性能,但是会影响直接内存的释放