I am trying to reduce the performance/garbage collection costs of logging statements. I want to have lots of logging statements that I could enable for debugging, but also have a way to turn them off for fast production.
I ran a benchmark on calling the following methods:
public static final isLogging = false;
public static logObjs(Object[] params) {
if(isLogging)
System.out.println(params[0]);
}
public static log3Obj(Object a, Object b, Object c) {
if(isLogging)
System.out.println(a);
}
public static logInts(int a, int b, int c) {
if(isLogging)
System.out.println(a);
}
I benchmarked the functions with a driver method
long sum = 0;
for(int i = 0; i < 100000000; ++i) {
int a = i; int b = i+1; int c = i+2;
logFoo(a,b,c);
sum += a; }
logObjs(i, i+1, i+2) takes about 2 seconds for 1e8 iterations and produces lots of garbage. The sources are, I assume, autoboxing of integers and the Object[] creation for the variable # of parameters.
log3Obj produces a lot (though less) garbage and takes about 1.2 seconds; again, I assume the autoboxing still happens.
logInts is very fast (0.2 sec), just as fast as the loop with no function call.
So, the issue is that even though the function deterministically doesn't do anything, the autoboxing still happens. In my code, I'd actually prefer to have isLogging not be final, but rather have it be a runtime parameter, but in order to do that, this simpler case (where the compiler can prove that the function doesn't do anything) should run. Of course, I can replace all my logging statements with
if(isLogging)
logObjs(a, b, c);
but that's very inelegant. I thought this is something that the JIT should take care of. I've tried a bunch of compiler settings, but maybe there's something I'm missing? How do I make the code not generate so much garbage while doing nothing?