在Java中当我们要对数据进行更底层的操作时,一般是操作数据的字节(byte)形式,这时经常会用到ByteBuffer这样一个类。

ByteBuffer提供了两种静态实例方式:

  1. public static ByteBuffer allocate(int capacity)
  2. public static ByteBuffer allocateDirect(int capacity)

为什么要提供两种方式呢?这与Java的内存使用机制有关。

第一种分配方式产生的内存开销是在JVM中的,而另外一种的分配方式产生的开销在JVM之外,也就是系统级的内存分配。

当Java程序接收到外部传来的数据时,首先是被系统内存所获取,然后在由系统内存复制复制到JVM内存中供Java程序使用。

所以在另外一种分配方式中,能够省去复制这一步操作,效率上会有所提高。可是系统级内存的分配比起JVM内存的分配要耗时得多,所以并非不论什么时候allocateDirect的操作效率都是最高的。

以下是一个不同容量情况下两种分配方式的操作时间对照:

由图能够看出,当操作数据量非常小时,两种分配方式操作使用时间基本是同样的,第一种方式有时可能会更快,可是当数据量非常大时,另外一种方式会远远大于第一种的分配方式。

其中allocateDirect分配的字节缓冲区用中文叫做直接缓冲区(DirectByteBuffer),用allocate分配的ByteBuffer叫做堆字节缓冲区(HeapByteBuffer)..

其实根据类名就可以看出,HeapByteBuffer所创建的字节缓冲区就是在jvm堆中的,即内部所维护的java字节数组。

而DirectByteBuffer是直接操作操作系统本地代码创建的内存缓冲数组(c、c++的数组)。

由于DirectByteBuffer操作的缓冲区是通过操作系统本地代码创建的,对于java来说创建和销毁DirectByteBuffer更消耗性能。

而HeapByteBuffer内部是直接创建的java数组,对于java来说更快。

可以根据下面的测试代码测试:

github源码地址

package NIO_FileChannel;import java.nio.ByteBuffer;public class DirectAndHeapSpeedCompare {public static void main(String[] args) {directAndHeapSpeedCompare();}private static void directAndHeapSpeedCompare() {int length = 10000;heapExecuteTime(length);directExecuteTime(length);}private static void directExecuteTime(int length) {long startTime = System.currentTimeMillis();ByteBuffer[] byteBufferArray = new ByteBuffer[length];for (int i = 0; i < length; i++) {byteBufferArray[i] = ByteBuffer.allocateDirect(1024);}long endTime = System.currentTimeMillis();System.out.println("创建" + length + "个DirectByteBuffer所消耗的时间:" + (endTime - startTime));}private static void heapExecuteTime(int length) {long startTime = System.currentTimeMillis();ByteBuffer[] byteBufferArray = new ByteBuffer[length];for (int i = 0; i < length; i++) {byteBufferArray[i] = ByteBuffer.allocate(1024);}long endTime = System.currentTimeMillis();System.out.println("创建" + length + "个HeapByteBuffer所消耗的时间:" + (endTime - startTime));}
}

创建10000个HeapByteBuffer所消耗的时间:12
创建10000个DirectByteBuffer所消耗的时间:17

那么为什么创建DirectByteBuffer比HeapByteBuffer性能差却还使用DirectByteBuffer呢?

答:创建DirectByteBuffer的确不如HeapByteBuffer快,但是本地IO(从操作系统本地获取数据,比如文件、socket网络数据)修改数据DirectByteBuffer是更快的。

因为:

HeapByteBuffer的缓冲区是java中的java数组,使用HeapByteBuffer读取一个文件,操作系统会先把文件读取到操作系统管理的内存中。

然后在把操作系统管理的这块内存的数据复制到jvm管理的内存(即HeapByteBuffer管理的java字节数组)中,然后HeapByteBuffer对java字节数组进行操作。。

而DirectByteBuffer

(1)先在操作系统内核所管理的内存缓冲区中(文件系统页)开辟一块内存空间(作为缓冲区),文件数据可以直接从操作系统复制到该缓冲区中

(2)用户写入和读取数据就可以直接操作这块缓冲区。。。。比使用HeapByteBuffer少了一个步骤,效率自然提升了。

什么情况下使用DirectByteBuffer(ByteBuffer.allocateDirect(int))?

1、频繁的native IO,即缓冲区 中转 从操作系统获取的文件数据、或者使用缓冲区中转网络数据等

2、不需要经常创建和销毁DirectByteBuffer对象

3、经常复用DirectByteBuffer对象,即经常写入数据到DirectByteBuffer中,然后flip,再读取出来,最后clear。。反复使用该DirectByteBuffer对象。

而且,DirectByteBuffer不会占用堆内存。。也就是不会受到堆大小限制,只在DirectByteBuffer对象被回收后才会释放该缓冲区。

什么情况下使用HeapByteBuffer(ByteBuffer.allocate(int))?

1、同一个HeapByteBuffer对象很少被复用,并且该对象经常是用一次就不用了,此时可以使用HeapByteBuffer,因为创建HeapByteBuffer开销比DirectByteBuffer低。

(但是!!创建所消耗时间差距只是一倍以下的差距,一般一次只会创建一个DirectByteBuffer对象反复使用,而不会创建几百个DirectByteBuffer,

所以在创建一个对象的情况下,HeapByteBuffer并没有什么优势,所以,开发中要使用ByteBuffer时,直接用DirectByteBuffer就行了)

总结:

HeapByteBuffer和DirectByteBuffer

1、HeapByteBuffer就是创建效率高,读取和写入的效率低。

2、DirectByteBuffer是创建效率低,读取和写入的效率高。

NIO ByteBuffer的allocate与allocateDirect区别(HeapByteBuffer与DirectByteBuffer的区别)相关推荐

  1. NIO ByteBuffer 的 allocate 和 allocateDirect 的区别(HeapByteBuffer 和 DirectByteBuffer 的区别)

    ByteBuffer 中 NIO里用得最多的Buffer ,有两种实现方式:HeapByteBuffer基于Java堆的实现,而DirectByteBuffer 使用了 unsafed 的API 进行 ...

  2. ByteBuffer的allocate和allocateDirect区别

    在Java中当我们要对数据进行更底层的操作时,通常是操作数据的字节(byte)形式,这时常常会用到ByteBuffer这样一个类.ByteBuffer提供了两种静态实例方式: public stati ...

  3. ByteBuffer的allocate和allocateDirect

    在Java中当我们要对数据进行更底层的操作时,一般是操作数据的字节(byte)形式,这时经常会用到ByteBuffer这样一个类.ByteBuffer提供了两种静态实例方式: Java代码   pub ...

  4. ByteBuffer.allocate()与allocateDirect()的区别

    allocate()产生的是HeapByteBuffer的实例, 本质上是一个no direct buffer, allocateDirect()产生的是DirectByteBuffer的实例, 本质 ...

  5. java byte 释放内存_java java.nio.ByteBuffer.allocateDirect 导致内存泄露

    java能够经过java.nio.ByteBuffer.allocateDirect(capacity)直接运用non java heap(java堆外)的内存 . 一.运用意图: 1.拓荒数据缓冲区 ...

  6. java nio rewind_java.nio.ByteBuffer中的flip()、rewind()、compact()等方法的使用和区别

    java.nio.ByteBuffer 1. ByteBuffer中的参数position.limit.capacity.mark含义: position:表示当前指针的位置(下一个要操作的数据元素的 ...

  7. Classloader、NIO ByteBuffer.allocateDirect的回收 、一致性Hash

    比较多的东西,写的比较杂乱,以后会写一些自己复习到的内容,或者新学习到的东西,尽量让自己写的东西有价值,对一天学习的内容有一个总结. 一.Classloader 1.过程 1)加载:查找并加载类的二进 ...

  8. 13. 一步一图带你深入剖析 JDK NIO ByteBuffer 在不同字节序下的设计与实现

    一步一图带你深入剖析 JDK NIO ByteBuffer 在不同字节序下的设计与实现 让我们来到微观世界重新认识 Netty 在前面 Netty 源码解析系列 <聊聊 Netty 那些事儿&g ...

  9. 一步一图带你深入剖析 JDK NIO ByteBuffer 在不同字节序下的设计与实现

    让我们来到微观世界重新认识 Netty 在前面 Netty 源码解析系列 <聊聊 Netty 那些事儿>中,笔者带领大家从宏观世界详细剖析了 Netty 的整个运转流程.从一个网络数据包在 ...

最新文章

  1. 名片DIY官方认证代码_【教程】DIYQQ动态名片
  2. python启蒙视频_python启蒙阶段
  3. Python中的numpy.zeros()
  4. 【个人笔记】OpenCV4 C++ 快速入门 12课
  5. L1-064 估值一亿的AI核心代码 (20 分)—团体程序设计天梯赛
  6. Java编程入门基础知识合集
  7. IDEA的介绍基础运用和优化还有各种功能(超级全!!多图!!)
  8. matlab判断星期几的语句,计算某一天是星期几的matlab程序
  9. 电脑公司GHOST WIN7 装机旗舰版 2013 09
  10. hp计算机如何重装win7,为你解答惠普电脑怎么重装win7系统
  11. 浏览器 user agent
  12. 新手如何选择外汇交易平台?
  13. 如何删除卸载苹果mac电脑应用软件没有残留垃圾
  14. Java实现将本地.html文件以.docx文件格式导出并添加水印
  15. python怎么编写口算题_来出口算题—— Python编程
  16. 浦发银行面试问题总结
  17. rk3399 android 9.0 frameworks中添加导航栏状态栏控制
  18. LeetCode刷题(61)~找出数组中的幸运数
  19. 如何实现,一人账号,全村人(宿舍)无限上网——校园网卡BUG篇-无锡科技职业学院
  20. C# WFM调用百度地图

热门文章

  1. 谈谈过去十五年身处教师家庭是什么感受
  2. Java基础学习之数据结构:利用栈和队列完成表达式解析
  3. group by 取最新或者最后的一条数据
  4. 发现最优秀的人工智能对话体验
  5. RabbitMQ第一种消息模型--直连模型
  6. QT 调用vs写的dll 使用OutputDebugString输出调试信息
  7. 解决微信QQ邮箱提醒收不到通知的问题
  8. 一文读懂工业以太网设备的发展史
  9. 御黑行动来袭--助力三月重保,构筑安全防线!
  10. 用Go语言 轻松实现插入排序 (Golang经典编程案例)