Monday, October 17, 2005

java NIO allocate vs allocateDirect

Java NIO (new IO) came up with JDK 1.4.

As of now there is only one book out there that deals with it :-
http://www.amazon.com/exec/obidos/tg/detail/-/0596002882/104-4162257-7590320?v=glance

I wanted to have a look at some of the new stuff, and looked at some material on the net.

Buffers are to pimitive types what collections are to Objects.

What interests me is that the new java nio ByteBuffer class has two ways to create a new ByteBuffer i.e the static methods allocate and allocateDirect.

As i understand allocateDirect, will allocate it directly in the OS memory space and not in the JVM space. It has the primary advantage of not using up too much JVM memory for large files or other hige primitive type data.

Here are the common method used for the code below:-
static void logTime(String seq){
System.out.println(seq + " : " + new Date(System.currentTimeMillis()));
}


static void showBufferProperties( Buffer buf,String name){

System.out.println( "Buffer Properties for " + name + "\n capacity=" + buf.capacity() + " limit=" + buf.limit() + " position=" + buf.position());

}



I tried out the following :-


logTime("1");
ByteBuffer buf5 = ByteBuffer.allocate(300000000);
logTime("1a");
for(int i = 0; i
buf5.putDouble(1.0/3.0).
putFloat((float)(1.0/6.0)).
putLong(Long.MAX_VALUE);
}
showBufferProperties(buf5,"buf5");
logTime("2");

And got this result.


1 : Mon Oct 17 10:20:19 BST 2005
java.lang.OutOfMemoryError
Exception in thread "main"



Then i tried this :-


logTime("3");
ByteBuffer buf6 = ByteBuffer.allocateDirect(300000000);
logTime("3a");
for(int i = 0; i
buf6.putDouble(1.0/3.0).
putFloat((float)(1.0/6.0)).
putLong(Long.MAX_VALUE);
}
showBufferProperties(buf6,"buf6");
logTime("4");


And got this result:-


3 : Mon Oct 17 10:22:53 BST 2005
3a : Mon Oct 17 10:23:00 BST 2005
Buffer Properties for buf6
capacity=300000000 limit=300000000 position=60000000
4 : Mon Oct 17 10:23:09 BST 2005




So clearly for huge files allocateDirect does work well as compared to allocate which give an out of memory error.


Here is what the java doc says :-


Direct vs. non-direct buffers


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. It is therefore recommended that such buffers be used 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. 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 either return an arbitrary value, have no visible effect, or cause an unspecified exception to be thrown.

Whether a byte buffer is direct or non-direct may be determined by invoking its
isDirect method.


So it is as good as reading or writing to system memory directy using JNI and then wrapping it with java code. The additional advantage is it does not use the JVM memory space.



I can also see the advantage of using this if there are many smaller files all open at the same time for a application. It could use up the jvm heap space very fast. JVM is a heap space meant for objects. To use it up for reading or writing files would not be so good.

Also i guess it is better if we use the OS for what it does best i.e handle files.



I can see that this new bytebuffer class will go a long way to help with the above.

Also the other advantage v/s doing the same with JNI is that this is platform neutral. Just say allocateDirect and the java code will use the OS memory. JNI code might have to be coded for each OS on which you will deploy the application.

Note:-

It seems that for direct buffers hasArray method returns true meaning that it does have a array behind it , and for non-direct buffers the hasArray method returns false that is it does not have a backing array. The array can be retrieved by invoking the the array() method on ByteBuffer class.

2 Comments:

Blogger Unknown said...

too late :) but basically you helped my in solving an issue, thanks :)

3:25 AM  
Blogger robert said...

You got "true" and "false" mixed up in your trailing note: direct buffers (and those who are read only for obvious reasons) will return "false" for hasArray() - others return "true". You can look at the implementation btw.

7:47 AM  

Post a Comment

<< Home