ByteBuffer 提供了两种方式创建缓冲区,一个是在heap内分配即DirectBuffer,一个是在heap外分配。一个比较普遍的说法是,heap外分配的内存不太好把控,JVM不会回收其内存。然而事实上真的如此吗?我做了一个实验,我写了一个NIO服务端程序不断读取客户端发送过来的内容,然后回写到客户端。回写的时候用了DirectBuffer, 并且开辟的内存故意设的比较大128M。请看如下服务器代码片段。
/** * 处理读取客户端发来的信息 的事件 * @param key * @throws IOException */ public void read(SelectionKey key) throws IOException{ // 服务器可读取消息:得到事件发生的Socket通道 SocketChannel channel = (SocketChannel) key.channel(); // 创建读取的缓冲区 ByteBuffer buffer = ByteBuffer.allocate(256); // ByteBuffer buffer =ByteBuffer.allocateDirect(1024*1024); channel.read(buffer); byte[] data = buffer.array(); String msg = new String(data).trim(); System.out.println("服务端收到信息:"+msg); //ByteBuffer outBuffer = ByteBuffer.wrap(msg.getBytes()); ByteBuffer buffer2 =ByteBuffer.allocateDirect(1024*1024*128); buffer2.put(msg.getBytes()); channel.write(buffer2);// 将消息回送给客户端 System.out.println(buffer2.getClass().getName()); }
运行服务端程序后我们观察内存变化情况。我们先看看程序运行前CPU跟内存情况。
如红色标记出来的片段显示,内存非常平稳,cpu也几乎闲着。运行代码后,我们再观察
观察发现内存有了波动,但是基本稳定在2.91GB,比运行前增加的内存与direct buffer分配的内存大致相当。每次在内存波动比较大的情况下,CPU都有个冲浪,然后内存又被压下来,说明在回收内存,而并没有出现内存泄漏。因此JVM会做DirectBuffer的垃圾回收。
如果对JVM不放心,那我们可自己回收吗? 答案也是 "Big Yes"
我将代码增加清除的逻辑,并在分配内存之后睡眠10秒,然后再清除方便观察内存情况。发现分配后内存每次都会增加,但是清除之后立马内存就降下来了,请看代码不再贴图。有人会觉得奇怪这里为什么用反射去调用方法,原因是不同jre返回的class不一样,但是都提供了clean方法。
public void read(SelectionKey key) throws IOException{ // 服务器可读取消息:得到事件发生的Socket通道 SocketChannel channel = (SocketChannel) key.channel(); // 创建读取的缓冲区 ByteBuffer buffer = ByteBuffer.allocate(256); // ByteBuffer buffer =ByteBuffer.allocateDirect(1024*1024); channel.read(buffer); byte[] data = buffer.array(); String msg = new String(data).trim(); System.out.println("服务端收到信息:"+msg); //ByteBuffer outBuffer = ByteBuffer.wrap(msg.getBytes()); ByteBuffer buffer2 =ByteBuffer.allocateDirect(1024*1024*128); buffer2.put(msg.getBytes()); channel.write(buffer2);// 将消息回送给客户端 clean(buffer); } public void clean(ByteBuffer buffer){ try { System.out.println("buffer已分配,睡10秒钟,请注意观察内存变化,,,"); Thread.sleep(10000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } try { Method cleanerMethod = buffer.getClass().getMethod("cleaner"); cleanerMethod.setAccessible(true); Object cleaner = cleanerMethod.invoke(buffer); Method cleanMethod = cleaner.getClass().getMethod("clean"); cleanMethod.setAccessible(true); cleanMethod.invoke(cleaner); Thread.sleep(3000); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } }
既然DirectBuffer效率也高,回收也没问题,那为何不用DirectBuffer呢? 答案是,DirectBuffer的创建跟回收会比Heap的开销大,对于字节数不多的通信,两者甚至heap的缓冲效率略高,如果DirectBuffer会持续长时间或者会被重用,那用DirectBuffer会是不错的选择。因此说大文件的传输用DirectBuffer是比较合适的。
相关推荐
java api之ByteBuffer基础、应用场景、实战讲解 文档中有丰富的例子代码实现
仿安卓ByteBuffer 完美组包、拆包
描述:为了解决java与C结构通信过程中结构体解析问题。 主要功能:能友好的用java处理任何发送的C结构体对象,并且能发送java对象转换成C结构体接收的二进制。 功能说明 1、基于spring框架开发 2、对于结构体定义...
使用nio byteBuffer 实现按行读取文件(大文件) 在window/linux/macOS上均测试通过 对于中文乱码也已处理成功 完整注释,可随需求更改 有问题请邮件:mly610865580@126.com
【IT十八掌徐培成】Java基础第26天-05.ByteBuffer-mark-pos-limit-cap-flip.zip
NULL 博文链接:https://chinaestone.iteye.com/blog/468138
NULL 博文链接:https://zheng12tian.iteye.com/blog/1094811
java实现使用javolution完成数据接收过程中大小端转换的问题
Java-NIO-Programming-Cookbook英文版和配套源代码。有一个使用DirectByteBuffer和Non-Direct Buffer文件读取速度的对比实验程序和测试结果。
ByteBuffer buffer = ByteBuffer.allocate(32).order(ByteOrder.LITTLE_ENDIAN); // use the documents utility class to write the document into the buffer BsonDocuments.writeTo(buffer, ...
java api之ByteBuffer基础、应用场景、实战讲解
Android
易语言汇编版ByteBuffer源码。主要用于各种网络协议的组包 具体用法可以点上面的网址 功能和jAVA的一样。@10371178。Tags:易语言汇编版ByteBuffer源码。
ByteBuffer *buffer = [ByteBuffer initWithOrder: ByteOrderLittleEndian]; #输入数据 - ( void )put:( Byte )b; - ( void )putByteBuffer:(ByteBuffer*)bb; - ( void )putData:( NSData *)data; - ( void )...
本类,是专门为了处理大文件,按行读取开发的类。 采用读文件的缓存 fbb 1024*5 行缓存 bb 256 字节 设计思想: 每次通过nio读取字节到 fbb中 然后对fbb自己中的内容进行行判断即 10 回车 13 行号 0 文件结束 ...
主要解决从流中获取数据,缓存,拆解,可用于TCP粘包问题
java socket处理硬件传过来的16进制数据的工具类,包含大小端转换、byte[]数组转换为16进制的字符串、byte[]转ByteBuffer、16进制字符串转换为byte数组等
java中的中文乱码(其中介绍了中国近现代的汉字革命) java中为什么会产生中文乱码 如何解决java中的中文乱码
本文实例讲述了Android在JNI中使用ByteBuffer的方法。分享给大家供大家参考。具体如下: 一、ByteBuffer 定义 在NIO中,数据的读写操作始终是与缓冲区相关联的(读取时信道(SocketChannel)将数据读入缓冲区,写入时...