Reflection, Field.get, and Class.isAssignableFrom
I'm hitting a major performance problem while using reflection. I'm reading data off of disk as a sequence of bytes, and decoding the bytes and storing them in Java object instances (I'm decoding COBOL/EBCDIC files). In my test app, I read 1,000,000 lines of text, each about 70 bytes, and each line gets decoded and stored into a Java object, and then doing some calculations.
The problem is that the Field.get() call is taking far longer than all other processing, *including* actually reading data from disk. Here is the top part of the "hprof" output:
rank self accum count trace method
1 33.05% 33.05% 307 300380 java.lang.Class.isAssignableFrom
2 7.97% 41.01% 74 300388 java.lang.Class.isAssignableFrom
3 2.91% 43.92% 27 300395 java.lang.Class.isAssignableFrom
4 2.26% 46.18% 21 300411 java.lang.Double.doubleToLongBits
5 2.15% 48.33% 20 300404 sun.nio.cs.SingleByteEncoder.encodeArrayLoop
6 1.83% 50.16% 17 300420 sun.nio.cs.SingleByteDecoder.decode
7 1.72% 51.88% 16 300449 java.io.DataOutputStream.write
8 1.61% 53.50% 15 300398 sun.nio.cs.SingleByteDecoder.decode
9 1.51% 55.01% 14 300422 sun.nio.cs.SingleByteEncoder.encodeArrayLoop
10 1.51% 56.51% 14 300423 java.lang.StrictMath.floor
11 1.40% 57.91% 13 300473 sun.nio.cs.SingleByteEncoder.encodeArrayLoop
And here is one of the stack traces:
So we can see that almost half of the time the app is in the Class.isAssignableFrom() method. I can see from the stack traces in the hprof output that all calls to Class.isAssignableFrom() originate from Field.get().
Looking at the source for Field.get(), I can't see any workaround. Does anyone have an suggestions for how I might be able to turn this checking off or speed it up? I've already called Field.setAccessible(true), which cleared up another bottleneck, but not this one.
It seems to me that there's a real design flaw here. I've got a Field instance and I call get() and pass an object of a particular class. Once this "isAssignableFrom" check passes, we know it will pass on all subsequent calls to get() with an instance of that same class. No need to keep checking on every call.