Java Direct ByteBuffer Example
This example shows the usage of direct ByteBuffer
.
ByteBuffer
is an abstract class, extends Buffer
and implements Comparable<ByteBuffer>
. This class is defined in the java.nio
package.
A buffer is a container for a fixed amount of data of a specific primitive type. There is a buffer class for each non-boolean primitive type. A ByteBuffer
is a sub class of Buffer
of byte
primitive type.
Byte Buffer
Byte buffers are distinguished in that they can be used as the sources and targets of I/O operations. They also support several features not found in the other buffer classes:
- A byte buffer can be allocated as a direct buffer.
- A byte buffer can be created by mapping a region of a file directly into memory.
- A byte buffer provides access to its content as either a heterogeneous or homogeneous sequence of binary data of any non-boolean primitive type, in either big-endian or little-endian byte order.
Direct and Non-direct Byte Buffers
For 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
allocateDirect()
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.
- A direct byte buffer may also be created by mapping a region of a file directly into memory. See
MappedByteBuffer
for details.
Whether a byte buffer is direct or non-direct may be determined by invoking its isDirect()
method.
1. An Example
This example shows usage of a direct ByteBuffer
class.
First, the example program reads a file using a direct buffer, and then with a non-direct buffer. The times taken to complete the read operation are compared. The program reads a binary file (for example a video file of type .wmv
) of about 1.2 GB size. The program reads the file multiple times.
The following describes the example program code:
1.1. Create a direct byte buffer
ByteBuffer buffer = ByteBuffer.allocateDirect(1024 * 10);
1.2. Verify if buffer is direct
buffer.isDirect();
The isDirect()
method returns true
for a direct byte buffer and false
for an non-direct buffer.
1.3. Check if buffer has a backing array
buffer.hasArray();
The hasArray()
method returns false
for a direct buffer and true
for a non-direct buffer.
The array()
method of byte buffer class returns a byte array (byte []
) of the buffer’s contents. This is only valid for non-direct buffers. When used with direct buffers this method throws an exception: UnsupportedOperationException
1.4. Read the file
The input file is read using a FileChannel
into a direct byte buffer. The file is read multiple times (25). Each read is from the beginning to the end of file. The total time taken to complete all the reads is recorded and printed.
Next, the program is modified to use a non-direct byte buffer. Only, the following line of the program code is changed:
From:
ByteBuffer buffer = ByteBuffer.allocateDirect(1024 * 10);
To:
ByteBuffer buffer = ByteBuffer.allocate(1024 * 10);
The program is run again and the total time taken to complete all the reads is recorded and printed – this time using a non-direct byte buffer.
2. The Code
DirectByteBufferExample.java
import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.nio.file.Paths; import java.nio.file.Path; import java.util.Date; public class DirectByteBufferExample { public static void main (String [] args) throws Exception { long startTime = new Date().getTime(); Path path = Paths.get("testfile"); FileChannel fileChannel = FileChannel.open(path); ByteBuffer buffer = ByteBuffer.allocateDirect(1024 * 10); System.out.println("Is a direct buffer: " + buffer.isDirect()); System.out.println("Buffer has a backing array: " + buffer.hasArray()); System.out.println("Reading file... "); int noOfBytesRead = fileChannel.read(buffer); for (int i = 0; i < 25; i++) { while (noOfBytesRead != -1) { buffer.clear(); noOfBytesRead = fileChannel.read(buffer); } buffer.clear(); fileChannel.position(0); noOfBytesRead = fileChannel.read(buffer); } fileChannel.close(); long endTime = new Date().getTime(); System.out.println(""); System.out.println("Time taken (millis): " + (endTime - startTime)); } }
The above program reads a file using a direct byte buffer. To run the program with a non-direct byte buffer, replace the code on line 18 with the following:
ByteBuffer buffer = ByteBuffer.allocate(1024 * 10);
NOTE: For usage of file channels with byte buffers see: java.nio.channels.FileChannel Example
3. The Program Run
Run the program with direct buffer and then with the non-direct buffer. The following are the respective outputs. Note that the program was tested on Windows 7 OS and using Java SE 7 API.
3.1. The output
3.1.1. The direct buffer program output
Is a direct buffer: true Buffer has a backing array: false Reading file... Time taken (millis): 17062
3.1.2. The non-direct buffer output
Is a direct buffer: false Buffer has a backing array: true Reading file... Time taken (millis): 26395
From the two outputs note that there is a time improvement in reading the file using direct byte buffer. The time taken figures were consistent over multiple program runs of both direct and non-direct buffer usage.
4. Download Java Source Code
This was an example of Java Direct ByteBuffer
You can download the full source code of this example here: DirectByteBufferExample.zip