[Andreas]
Hi all,
For starters: it's not really a pressing matter ATM, but it may become
of relevance if we want to strive for a production-release. The matter
is somewhat related to the distinction between developer- and
user-directed logging.
It concerns the numerous log.debug() and log.trace() messages scattered
around. Just recently, I was reminded of a little Java trick that
emulates C's conditional compilation, which inspired me to pop this
question here.
As you are most likely well aware, every log.debug() generates bytecode
at compile-time, which leads to compiled classes being unnecessarily
large for general usage. In Java, there exists this little trick to
define a final debug() method:
final void debug(String msg) {
if (DEBUG) {
log.debug(msg);
}
}
The DEBUG boolean constant being defined in a central, easily
accessible place.
If subsequently, all log.debug() calls are replaced by mere debug(),
and one sets DEBUG to false, then the result at compile-time is that:
- there is no bytecode generated for the debug() methods (empty body)
That is true.
- since the method is final, and it has an empty body, the compiler can
optimize further and no bytecode will be generated for any call to it.
Not true for javac from jdk1.4.2. A call to the debug method is included
in the byte code. Perhaps other compilers does it differently.
Meaning also: possible string literals in the message do not take up
space in the internalized string-table, which in turn would be
beneficial for eventual runtime-calls to String.intern() (smaller table
=> decreased lookup-time)
Also not true for 1.4.2.
public class x {
public static final boolean DEBUG = false;
public static void main(String[] args) throws Exception {
new x();
}
public x() {
int i = 55;
debug("hello " + i + " world");
}
final void debug(String msg) {
if (DEBUG) {
System.out.println(msg);
}
}
}
Compiled from "x.java"
public class x extends java.lang.Object{
public static final boolean DEBUG;
public static void main(java.lang.String[]);
throws java/lang/Exception
Code:
0: new #1; //class x
3: dup
4: invokespecial #2; //Method "<init>":()V
7: pop
8: return
public x();
Code:
0: aload_0
1: invokespecial #3; //Method java/lang/Object."<init>":()V
4: bipush 55
6: istore_1
7: aload_0
8: new #4; //class StringBuffer
11: dup
12: invokespecial #5; //Method java/lang/StringBuffer."<init>":()V
15: ldc #6; //String hello
17: invokevirtual #7; //Method
java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
20: iload_1
21: invokevirtual #8; //Method
java/lang/StringBuffer.append:(I)Ljava/lang/StringBuffer;
24: ldc #9; //String world
26: invokevirtual #7; //Method
java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
29: invokevirtual #10; //Method
java/lang/StringBuffer.toString:()Ljava/lang/String;
32: invokevirtual #11; //Method debug:(Ljava/lang/String;)V
35: return
final void debug(java.lang.String);
Code:
0: return
}
All the string litterals and string concatination still exists in the
byte code.
Perhaps the JIT will detect the empty method and avoid the string
concatination, I have not tested that, but I doubt it.
regards,
finn