You can disregard protection levels by using reflection, but that kinda defeats the performance goal in a big way.
Up vote 8 down vote favorite 2 share g+ share fb share tw.
Some abstract methods from ByteBuffer are package private, and if I create package java. Nio, security exception is thrown. I would want to do that for performance reasons - getInt for example has about 10 method invocations, as well as quite a few if's.
Even if all checks are left, and only method calls are inlined and big/small endian checks are removed, tests that I've created show that it can be about 4 times faster. Java nio bytebuffer link|improve this question edited Jan 27 at 2:24Jonas12.2k741103 asked Mar 8 '09 at 22:34Sarmun382312 64% accept rate.
My top tips for NIO buffer performance: Use -server, make your methods small (so that they can be inlined into) and sometimes it's better to switch to byte. – Tom Hawtin - tackline Mar 9 '09 at 11:35 Similar question on thatsjava.com – finnw May 27 '11 at 9:51 +50 bounty for a way to circumvent the access restriction (tt cannot be done using reflection alone. Maybe there is a way using sun.misc.
Unsafe etc.?) – finnw May 27 '11 at 9:53 Related: stackoverflow.com/questions/462094/… and stackoverflow.com/questions/4682659/… – finnw May 27 '11 at 10:10 @finnw, which access restricton are you talking about? If you are talking about a plain system without a security manager all you need to do is get the private field theUnsafe – Peter Lawrey May 27 '11 at 14:54.
You can disregard protection levels by using reflection, but that kinda defeats the performance goal in a big way. You can NOT create a class in the java. Nio package - doing so (and distributing the result in any way) violates Sun's Java license and could theoretically get you into legal troubles.
I don't think there's a way to do what you want to do without going native - but I also suspect that you're succumbing to the temptation of premature optimization. Assuming that your tests are correct (which microbenchmarks are often not): are you really sure that access to ByteBuffer is going to be the performance bottleneck in your actual application? It's kinda irrelevant whether ByteBuffer.get() could be 4 times faster when your app only spends 5% of its time there and 95% processing the data it's fetched.
Wanting to bypass all checks for the sake of (possibly purely theoretical) performance does not sound a good idea. The cardinal rule of performance tuning is "First make it work correctly, THEN make it work faster". Edit: If, as stated in the comments, the app actually does spend 20-40% of its time in the ByteBuffer methods and the tests are correct, that means a speedup potential of 15-30% - significant, but IMO not worth starting to use JNI or messing with the API source.
I'd try to exhaust all other options first: Are you using the -server VM? Could the app be modified to make fewer calls to ByteBuffer rather than trying to speed up those it does make? Use a profiler to see where the calls are coming from - perhaps some are outright unnecessary Maybe the algorithm can be modified, or you can use some sort of caching.
I don't think reflection would help here (I was going to say the same thing)... I think what he wants to do is to actually change the method to avoid the check. But perhaps I read it wrong... but regardless reflection will negate any speed improvements. – TofuBeer Mar 8 '09 at 23:13 I would like either to extends HeapByteBuffer, and change few methods, or extend ByteBuffer and write all the methods.
And my program is very heavily using it, about 20-40% is going to ByteBuffer methods, so if it can be done, it will improve performance significantly. – Sarmun Mar 8 '09 at 23:28 I happen to be playing around with ByteBuffers myself right now... I hit a performance thing (went from 4 seconds to 22 seconds, and now back to 4 seconds). Have you used a profiler to be sure of where the slowdown is (in my case I was making unneeded copies of the buffer).
– TofuBeer Mar 8 '09 at 23:54 @TofuBeer I believe reflection actually could be used as intended, to bypass rather than change the methods in question - but yeah, totally pointless when you motivation is performance. – Michael Borgwardt Mar 9 '09 at 0:15 I am using -server VM. Is there a way to inline method calls more aggressively?
(because if all methods 3-4 level deep are inlined there, it would make significant improvement - I don't think vm is doing that currently, but don't know why) I also think that it's not worth messing with JNI. – Sarmun Mar 9 '09 at 1:15.
You cant extend ByteBuffer and thanks God for. You cant extend because there are no protected c-tors. Why thank god part?
Well, having only 2 real subclasses ensures that the JVM can Heavily optimizes any code involving ByteBuffer. Last, if you need to extend the class for real, edit the byte code, and just add protected attribute the c-tor and public attribute to DirectByteBuffer (and DirectByteBufferR). Extending the HeapBuffer serves no purposes whatsoever since you can access the underlying array anyways use -Xbootclasspath/p and add your own classes there, extend in the package you need (outside java.
Nio). That's how it's done. Another way is using sun.misc.
Unsafe and do whatever you need w/ direct access to the memory after address(). I would want to do that for performance reasons - getInt for example has about 10 method invocations, as well as quite a few if's. Even if all checks are left, and only method calls are inlined and big/small endian checks are removed, tests that I've created show that it can be about 4 times faster.
Now the good part, use gdb and check the truly generated machine code, you'd be surprised how many checks would be removed. I can't imagine why a person would want to extend the classes. They exist to allow good performance not just OO polymorph execution.
Edit: How to declare any class and bypass Java verifier On Unsafe: Unsafe has 2 methods that bypass the verifier and if you have a class that extends ByteBuffer you can just call any of them. You need some hacked version (but that's super easy) of ByteBuffer w/ public access and protected c-tor just for the compiler. The methods are below.
You can use 'em on your own risk. After you declare the class like that you can even use it w/ new keyword (provided there is a suitable c-tor) public native Class defineClass(String name, byte b, int off, int len, ClassLoader loader, ProtectionDomain protectionDomain); public native Class defineClass(String name, byte b, int off, int len).
ByteBuffer is abstract so, yes, you can extend it... but I think what you want to do is extend the class that is actually instantiated which you likely cannot. It could also be that the particular one that gets instantiated overrides that method to be more efficient than the one in ByteBuffer. I would also say that you are likely wrong in general about all of that being needed - perhaps it isn't for what you are testing, but likely the code is there for a reason (perhaps on other platforms).
If you do believe that you are correct on it open a bug and see what they have to say. If you want to add to the nio package you might try setting the boot classpath when you call Java. It should let you put your classes in before the rt.
Jar ones. Type java -X to see how to do that, you want the -Xbootclasspath/p switch.
1 ByteBuffer has package private abstract _set and _get methods, so you couldn't override it. And also all the constructors are package private, so you cannot call them. – Sarmun Mar 8 '09 at 23:21 You can call them via reflection (get the method and call setAccessible(true) on it), but that will be slow.
You should be able to add a class via the bootclasspath, but as was pointed out you cannot ship it. – TofuBeer Mar 8 '09 at 23:52 "you can extend it" doesn't to me say "you can extend it if you put your subclass on the bootclasspath". If you mess with the boots then you can do what you want.
Very close to a -1 from me... – Tom Hawtin - tackline Mar 9 '09 at 11:30 If he wants to do proper testing that is what he has to do. Note I said file a bug against Sun about it. In context it is a valid thing to do.
– TofuBeer Mar 9 '09 at 14:50.
50 bounty for a way to circumvent the access restriction (tt cannot be done using reflection alone. Maybe there is a way using sun.misc. Unsafe etc.?) Answer is: there is no way to circumvent all access restrictions in Java.
Sun.misc. Unsafe works under the authority of security managers, so it wo ByteBuffer has package private abstract _set and _get methods, so you couldn't override it. And also all the constructors are package private, so you cannot call them.
Reflection allows you to bypass a lot of stuff, but only if the security manager allows it. There are many situations where you have no control on the security manager, it is imposed on you. If your code were to rely on fiddling with security managers, it would not be 'portable' or executable in all circumstances, so to speak.
The bottom line of the question is that trying to override byte buffer is not going to solve the issue. There is no other option than implementing a class yourself, with the methods you need. Making methods final were you can will help the compiler in its effort to perform optimizations (reduce the need to generate code for runtime polymorphism & inlining).
Finnw There is no way sun.misc. Unsafe or anything else can help circumventing the access restriction. – JVerstry May 27 '11 at 20:14 @JVersty, Unsafe is rightly named, but there is always a way to circumvent access control unless you have a SecurityManager/Access control to explicitly prevent it.
Even then, if you have access to starting the JVM you can do anything you wish. – Peter Lawrey May 29 '11 at 13:33 @Peter Lawrey We are saying the same thing. Unsafe is not key in circumventing access or not.
The security manager is. – JVerstry May 29 '11 at 15:41 what Peter says is exactly true, if you start the VM you can do whatever you like. If the code is run in a tight security box, well there must be a reason for and most likely the overhead of the security checks would outweight any improvements introduced by Unsafe.
– bestsss May 29 '11 at 16:56.
The simplest way to get the Unsafe instances is via reflection. However if reflection is not available to you, you can create another instance. You can do this via JNI.
I tried in byte code, to create an instance WITHOUT calling a constructor, allowing you create an instance of an object with no accessible constructors. However, this id not work as I got a VerifyError for the byte code. The object has to have had a constructor called on it.
What I do is have a ParseBuffer which wraps a direct ByteBuffer. I use reflection to obtain the Unsafe reference and the address. To avoid running off the end of the buffer and killing the JVM, I allocate more pages than I need and as long as they are not touched no physical memory will be allocated to the application.
This means I have far less bounds checks and only check at key points. Using the debug version of the OpenJDK, you can see the Unsafe get/put methods turn into a single machine code instruction. However, this is not available in all JVM and may not get the same improvement on all platforms.
Using this approach I would say you can get about a 40% reduction in timings but comes at a risk which normal Java code does not have i.e. You can kill the JVM. The usecase I have is an object creation free XML parser and processor of the data contained using Unsafe compared with using a plain direct ByteBuffer.
One of the tricks I use in the XML parser is to getShort() and getInt() to examine multiple bytes at once rather than examining each byte one at a time. Using reflection to the the Unsafe class is an overhead you incurr once. Once you have the Unsafe instance, there is no overhead.
A Java Agent could modify ByteBuffer's bytecode and change the constructor's access modifier. Of course you'd need to install the agent at the JVM, and you still have to compile get your subclass to compile. If you're considering such optimizations then you must be up for it!
I've never attempted such low level manipulation. Hopefully ByteBuffer is not needed by the JVM before your agent can hook into it.
I'll add that JMockit uses the Java Agent approach and can instrument private constructors. Not sure what black magic it uses. – Peter Davis Jun 1 '11 at 6:14 why would do it one the fly?
You still need some bytecode enabled version to allow normal compilation cheating the compiler is also an option, of course, but a difficult one; or you can manually create the class file. Yet, if you have the modified class version and you can install any instrumentation, you can just alter the bootstrap path as easily. – bestsss Jun 1 '11 at 13:45.
I am answering the question you WANT the answer to, not the one you asked. Your real question is "how can I make this go faster? " and the answer is "handle the integers an array at a time, and not singly.
" If the bottleneck is truly the ByteBuffer.getInt() or ByteBuffer. GetInt(location), then you do not need to extend the class, you can use the pre-existing IntBuffer class to grab data in bulk for more efficient processing. Int totalLength = numberOfIntsInBuffer; ByteBuffer myBuffer = whateverMyBufferIsCalled; int block = new int1024; IntBuffer intBuff = myBuffer.asIntBuffer(); int partialLength = totalLength/1024; //Handle big blocks of 1024 ints at a time try{ for (int I = 0; I 0) { intBuff.
Get(block,0,partialLength); //Do final processing on ints } } catch BufferUnderFlowException bufo { //well, dang! } This is MUCH, MUCH faster than getting an int at a time. Iterating over the int array, which has set and known-good bounds, will also let your code JIT much tighter by eliminating bounds checks and the exceptions ByteBuffer can throw.
If you need further performance, you can tweak the code, or roll your own size-optimized byte to int conversion code. I was able to get some performance improvement using that in place of the IntBuffer methods with partial loop unrolling... but it's not suggested by any means.
That would work if the buffer contains only int's. But in my case buffer can contain different types, without large consecutive chunks containing single type, this will not help – Sarmun Jun 25 '11 at 5:17 Then work from a giant byte and roll your own equivalent to the int/byte conversion methods. Less safety checks, less conditions, and less exception handling and it may beat the ByteBuffer methods.
It's almost always faster to operate on primitives directly when possible, because loops can be optimized more tightloy. – BobMcGee Jun 25 '11 at 5:32.
I cant really gove you an answer,but what I can give you is a way to a solution, that is you have to find the anglde that you relate to or peaks your interest. A good paper is one that people get drawn into because it reaches them ln some way.As for me WW11 to me, I think of the holocaust and the effect it had on the survivors, their families and those who stood by and did nothing until it was too late.