Measuring the time to create and destroy a simple object
From Effective Java 2nd Edition Item 7: Avoid Finalizers
"Oh, and one more thing: there is a severe performance penalty for using finalizers. On my machine, the time to create and destroy a simple object is about 5.6 ns. Adding a f开发者_Go百科inalizer increases the time to 2,400 ns. In other words, it is about 430 times slower to create and destroy objects with finalizers."
How can one measure the time to create and destroy an object? Do you just do:
long start = System.nanoTime();
SimpleObject simpleObj = new SimpleObject();
simpleObj.finalize();
long end = System.nanoTime();
long time = end - start;
That only measures the time to execute the finalize method. The vast majority of the cost of finalization will be in the special handling that the GC has to perform.
Instead of futilely trying to microbenchmark this, as Tom Hawtin said above, the best approach is to examine the time to do a few hundred thousand cycles of creation and destruction, and divide by number of cycles.
This approach is the best in a lot of situations where the code you write is not the only code involved - where you're dependent on system calls, or external resources.
I think that's what Joshua Bloch did in this case, but my copy is upstairs and I'm feeling lazy.
You could request the Runtime to perform Garbage collection via Runtime.gc()
, but the Garbage Collector is not required to perform it right there and then:
- The
finalize()
method is not to be called by you, but by the Garbage Collector - You could simply set the
simpleObj
tonull
, then call the Garbage collection to achieve a more realistic scenario
One possible solution is to rely on the java.lang.ref
package, which only supports a limited degree of interactions with the garbage collector.
The result of measurement couldn't be accurate, as it's hard to know the real ending of an object. I believe Joshua must have another approach to measure time, maybe head to JVM itself.
PhantomReference
references nearest to end of life cycle of an object. In other words, the object is phantom reachable.
public class WithoutFinalizationV1 {
public static void main(String[] args) {
ReferenceQueue<WithoutFinalizationV1> queue = new ReferenceQueue<>();
long start = System.nanoTime();
PhantomReference<WithoutFinalizationV1> rf = new PhantomReference<>(
new WithoutFinalizationV1(), queue);
System.gc(); //advise JVM to do GC
Object x = null;
int waitCount = -1;
do{
x = queue.poll();
waitCount++;
} while(x == null);
//only need this time point
System.out.println("WithoutV1 "+ waitCount + " " + (System.nanoTime() - start));
}
}
Run several times, the world record is 5394860ns, far from 5.6ns.
After adding
@Override
protected void finalize() throws Throwable {
}
the result is 5632208ns.
Here is an extract from a related post I wrote.
精彩评论