Tricks and Tips with NIO part VI: Heap, View or Direct ByteBuffer, which one perform the best?
Choosing the right byte buffer is not simple. Correct me if I’m wrong, but there is little documentation about which type of byte buffer to choose when writing scalable server. So here is some informal observations I’ve made when using the Grizzly WebServer
There is three types of byte buffer:

- Direct Byte Buffer [ByteBuffer.allocateDirect()]: Given a direct byte buffer, the Java virtual machine will make a best effort to perform native I/O operations directly upon it.
- Heap Byte Buffer [ByteBuffer.allocate()]: A byte buffer backed by a byte array.
- View Byte Buffer [ByteBuffer.slice()]: a byte buffer whose content is a shared subsequence of direct or heap byte buffer’s content.
Since no data/benchmarks where available on the topic at the time we’ve written Grizzly, the type is easily configurable via system properties. For the view byte buffer, Grizzly creates a very large one and slice it like this:
68 public synchronized static ByteBuffer allocateView(int size, boolean direct){
69 if (byteBuffer == null ||
70 (byteBuffer.capacity() - byteBuffer.limit() < size)){
71 if ( direct )
72 byteBuffer = ByteBuffer.allocateDirect(capacity);
73 else
74 byteBuffer = ByteBuffer.allocate(capacity);
75 }
76
77 byteBuffer.limit(byteBuffer.position() + size);
78 ByteBuffer view = byteBuffer.slice();
79 byteBuffer.position(byteBuffer.limit());
80
81 return view;
82 }
I didn’t run any micro benchmark, but here is some simple results using Grizzly WebServer.I didn’t set any special VM config, just the Grizzly out of the box configuration. For stressing the server, I’ve used ab, which is not the best/viable tool for benchmarking but the easiest to use. The JDK version used is:
java version "1.6.0"
Java(TM) SE Runtime Environment (build 1.6.0-b105)
Java HotSpot(TM) Client VM (build 1.6.0-b105, mixed mode, sharing)
I’ve run 100 times the following command and calculated the means:
% ab -q -k -n1000 -c600
and got the following result.
Direct ByteBuffer: 2241 tx/s with the following config:
% java -Dcom.sun.enterprise.web.connector.grizzly.useDirectByteBuffer=true
-jar grizzly-framework.jar 8080 /s1/domains/domain1/docroot/
Jan 23, 2007 12:10:58 PM
INFO:
Grizzly configuration for port 8080
maxThreads: 5
minThreads: 5
ByteBuffer size: 8192
useDirectByteBuffer: true
useByteBufferView: false
maxHttpHeaderSize: 8192
maxKeepAliveRequests: 256
keepAliveTimeoutInSeconds: 30
Heap ByteBuffer: 2269 tx/s with the following config:
% java -Dcom.sun.enterprise.web.connector.grizzly.useDirectByteBuffer=false
-jar grizzly-framework.jar 8080 /s1/domains/domain1/docroot/
Jan 23, 2007 12:19:34 PM
INFO:
Grizzly configuration for port 8080
maxThreads: 5
minThreads: 5
ByteBuffer size: 8192
useDirectByteBuffer: false
useByteBufferView: false
maxHttpHeaderSize: 8192
maxKeepAliveRequests: 256
keepAliveTimeoutInSeconds: 30
View Direct ByteBuffer: 2304 tx/s with the following config:
% java -Dcom.sun.enterprise.web.connector.grizzly.useByteBufferView=true
-Dcom.sun.enterprise.web.connector.grizzly.useDirectByteBuffer=true
-jar grizzly-framework.jar 8080 /s1/domains/domain1/docroot/
Jan 23, 2007 12:31:01 PM
INFO:
Grizzly configuration for port 8080
maxThreads: 5
minThreads: 5
ByteBuffer size: 8192
useDirectByteBuffer: true
useByteBufferView: true
maxHttpHeaderSize: 8192
maxKeepAliveRequests: 256
keepAliveTimeoutInSeconds: 30
View Heap ByteBuffer: 2484 tx/s with the following config:
% java -Dcom.sun.enterprise.web.connector.grizzly.useByteBufferView=true
-Dcom.sun.enterprise.web.connector.grizzly.useDirectByteBuffer=false
-jar grizzly-framework.jar 8080 /s1/domains/domain1/docroot/
Jan 23, 2007 12:38:43 PM
INFO:
Grizzly configuration for port 8080
maxThreads: 5
minThreads: 5
ByteBuffer size: 8192
useDirectByteBuffer: false
useByteBufferView: true
maxHttpHeaderSize: 8192
maxKeepAliveRequests: 256
keepAliveTimeoutInSeconds: 30
Surprisingly, the views from an heap byte buffer are always performing better. But before drawing conclusion, I also did similar test using Apache JMeter and got the same kind of results. Hence I’m tempted to conclude that Heap Byte Buffer will always perform better, and views from heap byte buffer is the type to use when possible. As usual, it might be Grizzly specific numbers, so I recommend you test the various type before making a choice….but I can bet view byte buffer will always perform the best! Of course, if someone has time to write a micro benchmark, make sure you drop your results here.
_uacct = “UA-3111670-1″;
urchinTracker();
