NIO ByteBuffer的allocate与allocateDirect区别(HeapByteBuffer与DirectByteBuffer的区别)
在Java中当我们要对数据进行更底层的操作时,一般是操作数据的字节(byte)形式,这时经常会用到ByteBuffer这样一个类。
ByteBuffer提供了两种静态实例方式:
- public static ByteBuffer allocate(int capacity)
- 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来说更快。
可以根据下面的测试代码测试:
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的区别)的更多相关文章
- ByteBuffer的allocate和allocateDirect区别
ByteBuffer的allocate和allocateDirect区别 在Java中当我们要对数据进行更底层的操作时,通常是操作数据的字节(byte)形式,这时常常会用到ByteBuffer这样一个 ...
- ByteBuffer的allocate和allocateDirect
在Java中当我们要对数据进行更底层的操作时,一般是操作数据的字节(byte)形式,这时经常会用到ByteBuffer这样一个类.ByteBuffer提供了两种静态实例方式: public stati ...
- java nio中,HeapByteBuffer与DirectByteBuffer的区别
HeapByteBuffer,顾名思义,是写在jvm堆上面的一个buffer,底层的本质是一个数组,用类封装维护了很多的索引(limit/position/capacity等) DirectByteB ...
- java.nio.ByteBuffer中的flip()、rewind()、compact()等方法的使用和区别
java.nio.ByteBuffer 1. ByteBuffer中的参数position.limit.capacity.mark含义: position:表示当前指针的位置(下一个要操作的数据元素的 ...
- 一步一图带你深入剖析 JDK NIO ByteBuffer 在不同字节序下的设计与实现
让我们来到微观世界重新认识 Netty 在前面 Netty 源码解析系列 <聊聊 Netty 那些事儿>中,笔者带领大家从宏观世界详细剖析了 Netty 的整个运转流程.从一个网络数据包在 ...
- Java--Stream,NIO ByteBuffer,NIO MappedByteBuffer性能对比
目前Java中最IO有多种文件读取的方法,本文章对比Stream,NIO ByteBuffer,NIO MappedByteBuffer的性能,让我们知道到底怎么能写出性能高的文件读取代码. pack ...
- HeapByteBuffer和DirectByteBuffer以及回收DirectByteBuffer
由于HeapByteBuffer和DirectByteBuffer类都是default类型的,所以你无法字节访问到,你只能通过ByteBuffer间接访问到它,因为JVM不想让你访问到它. 分配Hea ...
- jQuery方法区别:click() bind() live() delegate()区别
今天看到一篇jquery 事件的文章,自己写了个小例子,虽然2种方式都可以实现,但是不太明白,找了点资料 $("#box1").delegate("p",&qu ...
- JAVA基础之——三大特征、接口和抽象类区别、重载和重写区别、==和equals区别、JAVA自动装箱和拆箱
1 java三大特征 1)封装:即class,把一类实体定义成类,该类有变量和方法. 2)继承:从已有的父类中派生出子类,子类实现父类的抽象方法. 3)多态:通过父类对象可以引用不同的子类,从而实现不 ...
随机推荐
- IEDA创建Springboot项目
随着技术的更新对于开发速度的追求,我们越来越不能忍受的是Spring框架对于集成开发以后大量的配置问题.所以SprigBoot应运而生,SpringBoot框架其实就是在Spring框架的外边包裹上了 ...
- Java数据库连接组件C3P0和DBCP
C3P0连接池组件 开源数据库连接池组件 jar包:c3p0-0.9.2.jar和mchange-commons-java-0.2.2.3.jar 支持JDBC3规范和JDBC2的标准扩展 使用项目H ...
- typeof运算对于null会返回“Object"
您也许会问,为什么 typeof 运算符对于 null 值会返回 "Object".这实际上是 JavaScript 最初实现中的一个错误,然后被 ECMAScript 沿用了.现 ...
- python中线程和进程的简单了解
python中线程和进程的简单了解 一.操作系统.应用程序 1.硬件:硬盘.cpu.主板.显卡........ 2.装系统(本身也是一个软件): 系统就是一个由程序员写出来的软件,该软件用于控制计 ...
- 第七周scrum会议
本周会议地点依旧 会议照片: 本周内容: 讨论了进行中的难点 我们正在分析图书馆首页的网页结构以及各种跳转的请求以及链接,为爬虫的实现奠定基础. flask框架我们也遇到了很多问题,正在进行官方文档的 ...
- Artificial Intelligence in Finance
https://sigmoidal.io/real-applications-of-ai-in-finance/ Artificial Intelligence is taking the finan ...
- mongo db 去除 _class 字段
import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.NoSuc ...
- zzulioj - 2600: 有多少天?
题目链接:http://acm.zzuli.edu.cn/problem.php?id=2600 题目描述 小D同学对日期类的问题很是有兴趣,已知1900-01-01是星期一,那么小D想知道给定两个年 ...
- SQL Server 迁移数据库 (二)分离和附加
分离和附加其实比导入和导出,步骤要少一些,但是数据量大的话,跨服务器拷贝数据文件可能要慢一些 1. 分离数据库 这里最好选择断开链接,断开之前要确保你记得数据库的路径,一般默认都是C:\Program ...
- Linux--部署Django项目
简单部署 1.安装虚拟环境virtualenvwrapper,创建虚拟环境目录,进入虚拟环境,我的虚拟环境目录叫venv2 [root@HH ~]# workon venv2 (venv2) [roo ...