tags:

views:

554

answers:

2

Is there any way to create class that extends ByteBuffer class?

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.

+2  A: 

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.

TofuBeer
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
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
"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
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
+4  A: 

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
Michael Borgwardt
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
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
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
@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
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
Best solution that currently comes to my mind, is to create MyByteBuffer (with same interface), and all classes in project to use that one, and to use ByteBuffer's array() to construct it and vice-versa.
Sarmun
You can redistribute modified boot classes under the appropriate GPL or JRL (Java Research Licence). I am not a lawyer. I do not speak for Sun. Etc.
Tom Hawtin - tackline
You most definitely cannot. Look at the LICENSE file that comes with your JDK, at clause D of the supplemental license terms (as of JDK 6).
Michael Borgwardt
did you allocate the bytebuffers as direct via the allocateDirect method?
TofuBeer
the openjdk you can modify it... but cannot call it Java (it is GPL, you can fork). The research license, IIRC, lets you make mods avaialble to other research licensees - neither is a real solution, but both are legally allowed (I am not a lawyer!)
TofuBeer