java.nio包提供了Buffer API,使得Java程序可以直接控制和运用缓冲区。
java.nio public abstract class Buffer extends Object
缓冲区是包在一个对象内的基本数据元素的数组。Buffer类相比简单数组的优点是它将关于数据的数据内容和信息包含在一个单一的对象中。Buffer类以及它的自定义子类定义了一个用于处理数据缓冲区的API。
参考文档:
http://docs.oracle.com/javase/7/docs/api/java/nio/Buffer.html
Thread safety:
Buffers are not safe for use by multiple concurrent threads. If a buffer is to be used by more than one thread then access to the buffer should be controlled by appropriate synchronization.
所有的缓冲区都有以下属性:
操作1—— 新建一个容量为10的Buffer:
操作2—— 向新建的缓冲区写入数据:buffer.put(....): (写模式下的 position 和 limit)
操作3 —— 反转flip(),切换到读模式:(读模式下的position和limit)
Buffer提供了用于改变以上3个属性的方法:
Buffer的分配:
要想获得一个Buffer对象首先要进行分配。每个Buffer类都有一个allocate()方法。
ByteBuffer buf = ByteBuffer.allocate(48); CharBuffer buf = CharBuffer.allocate(1024);
缓冲区提供的读写缓冲区的方法:
int bytesRead = inChannel.read(buf); // read into buffer
buf.put(127);
int bytesWritten = inChannel.write(buf); // read from buffer into channel
byte aByte = buf.get();
缓冲区的类型:
Buffer的局限性
Direct vs. non-direct buffers(Heap Buffer)
A byte buffer is either direct or non-direct. Given a direct byte buffer, the Java virtual machine will make a best effort to perform native I/O operations directly upon it. That is, it will attempt to avoid copying the buffer's content to (or from) an intermediate buffer before (or after) each invocation of one of the underlying operating system's native I/O operations.
A direct byte buffer may be created by invoking the allocateDirect factory method of this class. The buffers returned by this method typically have somewhat higher allocation and deallocation costs than non-direct buffers. The contents of direct buffers may reside outside of the normal garbage-collected heap, and so their impact upon the memory footprint of an application might not be obvious. It is therefore recommended that direct buffers be allocated primarily for large, long-lived buffers that are subject to the underlying system's native I/O operations. In general it is best to allocate direct buffers only when they yield a measureable gain in program performance.
A direct byte buffer may also be created by mapping a region of a file directly into memory. An implementation of the Java platform may optionally support the creation of direct byte buffers from native code via JNI. If an instance of one of these kinds of buffers refers to an inaccessible region of memory then an attempt to access that region will not change the buffer's content and will cause an unspecified exception to be thrown either at the time of the access or at some later time.
Whether a byte buffer is direct or non-direct may be determined by invoking its isDirect method. This method is provided so that explicit buffer management can be done in performance-critical code.
Direct Buffer vs. Heap Buffer
1、 劣势:创建和释放Direct Buffer的代价比Heap Buffer得要高;
2、 区别:Direct Buffer不是分配在堆上的,它不被GC直接管理(但Direct Buffer的JAVA对象是归GC管理的,只要GC回收了它的JAVA对象,操作系统才会释放Direct Buffer所申请的空间),它似乎给人感觉是“内核缓冲区(buffer in kernel)”。Heap Buffer则是分配在堆上的,或者我们可以简单理解为Heap Buffer就是byte[]数组的一种封装形式,查看JAVA源代码实现,Heap Buffer也的确是这样。
3、 优势:当我们把一个Direct Buffer写入Channel的时候,就好比是“内核缓冲区”的内容直接写入了Channel,这样显然快了,减少了数据拷贝(因为我们平时的read/write都是需要在I/O设备与应用程序空间之间的“内核缓冲区”中转一下的)。而当我们把一个Heap Buffer写入Channel的时候,实际上底层实现会先构建一个临时的Direct Buffer,然后把Heap Buffer的内容复制到这个临时的Direct Buffer上,再把这个Direct Buffer写出去。当然,如果我们多次调用write方法,把一个Heap Buffer写入Channel,底层实现可以重复使用临时的Direct Buffer,这样不至于因为频繁地创建和销毁Direct Buffer影响性能。
简单的说,我们需要牢记三点:
(1) 平时的read/write,都会在I/O设备与应用程序空间之间经历一个“内核缓冲区”。
(2) Direct Buffer就好比是“内核缓冲区”上的缓存,不直接受GC管理;而Heap Buffer就仅仅是byte[]字节数组的包装形式。因此把一个Direct Buffer写入一个Channel的速度要比把一个Heap Buffer写入一个Channel的速度要快。
(3) Direct Buffer创建和销毁的代价很高,所以要用在尽可能重用的地方。