I am trying to reduce the cost of garbage collection / assembly for logging. I want to have a lot of logging operators that I could enable for debugging, but also be able to disable them for fast production.
I conducted a test when 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 compared functions using the 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 a lot of garbage. The sources are, I suppose, autoboxing integers and creating Object [] for the # parameter variable.
log3Obj produces a lot (albeit less) of garbage and takes about 1.2 seconds; again, I guess autoboxing does happen.
logInts is very fast (0.2 sec), as fast as a loop without calling a function.
So, the problem is that although the function deterministically does nothing, autoboxing does occur. In my code, I would prefer isLogging not to be final, but rather it was a runtime parameter, but for this it is a simpler case (when the compiler can prove that the function does nothing) should work. Of course, I can replace all my logging statements.
if(isLogging) logObjs(a, b, c);
but it is very inelegant. I thought this is what JIT should take care of. I tried a bunch of compiler settings, but maybe something is missing there? How to make code not generate so much garbage without doing anything?