Dr. Dobb's Journal November 1997
Sheng's Optimization Trick
Accessing an object's field via the JNI typically requires a sequence of four API calls. In my first attempt to access the array of integers that hold the value of a mInt, the last call, GetIntArrayElements(), failed. After some debugging, I knew the first three calls were succeeding, so why was GetIntArrayElements() failing with a "JNI scalar array element type mismatch" error? Sun's Sheng Liang answered the question, showing me an error in the third call after all. That call, GetObjectField(), requires the object's handle as its second parameter, and I was accidentally passing a class handle. Instead of detecting that an incorrect type of handle was being passed, the JVM used it and returned a wildly wrong value, which I used as input to the fourth call, making it fail.
While JNI is an improvement over NMI, it still has some problems: It doesn't typecheck handles on JNI calls, so the JVM is prone to the same kind of API errors that plagued Windows programs in the past.
The performance trick Sheng showed me is simple: You can do the first two calls of this infamous four-call sequence once (when the native library is loaded), and cache the output of the second call, which is the fieldID of the field in question (see the cacheFID() call in Listing One). Then, perform calls three and four of the sequence in each method. (You really only need one call in cacheFID(): A static code member gets the class's handle as a parameter, so you don't need an explicit call to retrieve it.) You can safely cache and reuse this value because the fieldID for a given class and field never changes for any instance of that class. The second call in the sequence, GetFieldID(), is expensive, so caching it more than doubles the performance of the Add() method from 25,000 to 55,555 operations per second on a 133-MHz Pentium under Windows 95 using the JVM from Sun's JDK 1.1.1. If you want to run your own tests, you can run AddTime.java (also available electronically), which compares calling the methods Add() and testAdd(). testAdd() is simply a noncached version of Add().
-- L.G.
Copyright © 1997, Dr. Dobb's Journal