java heap buffer direct buffer_HeapByteBuffer和DirectByteBuffer以及回收DirectByteBuffer

由于HeapByteBuffer和DirectByteBuffer类都是default类型的,所以你无法字节访问到,你只能通过ByteBuffer间接访问到它,因为JVM不想让你访问到它。

分配HeapByteBuffer的方法是:

ByteBuffer.allocate(int capacity);参数大小为字节的数量

分配DirectByteBuffer的方法是:

ByteBuffer.allocateDirect(int capacity);//可以看到分配内存是通过unsafe.allocateMemory()来实现的,这个unsafe默认情况下java代码是没有能力可以调用到的,不过你可以通过反射的手段得到实例进而做操作,当然你需要保证的是程序的稳定性,既然叫unsafe的,就是告诉你这不是安全的,其实并不是不安全,而是交给程序员来操作,它可能会因为程序员的能力而导致不安全,而并非它本身不安全。

1、HeapByteBuffer与DirectByteBuffer,在原理上,前者可以看出分配的buffer是在heap区域的,其实真正flush到远程的时候会先拷贝得到直接内存,再做下一步操作(考虑细节还会到OS级别的内核区直接内存),其实发送静态文件最快速的方法是通过OS级别的send_file,只会经过OS一个内核拷贝,而不会来回拷贝;在NIO的框架下,很多框架会采用DirectByteBuffer来操作,这样分配的内存不再是在java heap上,而是在C heap上,经过性能测试,可以得到非常快速的网络交互,在大量的网络交互下,一般速度会比HeapByteBuffer要快速好几倍。

2、DirectByteBuffer这块区域不是在java heap上,那么这块内存的大小是多少呢?默认是一般是64M,可以通过参数:-XX:MaxDirectMemorySize来控制。

3、直接内存好,我们为啥不都用直接内存?请注意,这个直接内存的释放并不是由你控制的,而是由full gc来控制的,直接内存会自己检测情况而调用system.gc(),但是如果参数中使用了DisableExplicitGC(这个参数作用是禁止代码中显示调用GC),那么如何才能释放直接内存呢?

4、那么full gc不触发,我想自己释放这部分内存有方法吗?可以的,我们看到它的源码中DirectByteBuffer发现有一个:Cleaner,是用来搞资源回收的。DirectByteBuffer类是Default类型的,因此这个类无法直接引用到,是通过反射去找到cleaner的实例,进而调用内部的clean方法,那样做麻烦了,其实并不需要那么麻烦,因为DirectByteBuffer implements了DirectBuffer,而DirectBuffer本身是public的,所以通过接口去调用内部的Clear对象来做clean方法。

下面来做测试来证明这个程序是有效地回收的:

importjava.nio.ByteBuffer;importsun.nio.ch.DirectBuffer;public classDirectByteBufferCleaner {public static void clean(finalByteBuffer byteBuffer) {if(byteBuffer.isDirect()) {

((DirectBuffer)byteBuffer).cleaner().clean();

}

}

}public static void sleep(longi) {try{

Thread.sleep(i);

}catch(Exception e) {/*skip*/}

}public static void main(String []args) throwsException {

ByteBuffer buffer= ByteBuffer.allocateDirect(1024 * 1024 * 100);

System.out.println("start");

sleep(10000);

clean(buffer);

System.out.println("end");

sleep(10000);

}

这里分配了100M内存,为了将结果看清楚,在执行前,执行后分别看看延迟10s,请提前将OS的资源管理器打开,看看当前使用的内存是多少,如果你是linux当然是看看free或者用top等命令来看;本地程序我是用windows完成,在运行前机器的内存如下图所示:

e8fee9a1725f93ef7dd898c6bf8fe9f1.png

开始运行在输入start后,但是未输出end前,内存直接上升将近100m。

89022b76e669ab81b782caf52ed34f7b.png

在输入end后发现内存立即降低到2.47m,说明回收是有效的。

e8fee9a1725f93ef7dd898c6bf8fe9f1.png

此时可以观察JVM堆的内存,不会有太多的变化,注意:JVM本身启动后也有一些内存开销,所以不要将那个开销和这个绑定在一起;这里之所以一次性申请100m也是为了看清楚过程。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值