- 54 -
SockStreamLogger.reads, 1, one_byte, 0; return ret;
} public int readbyte b[] throws IOException {
int sz = in.readb; SockStreamLogger.reads, sz, b, 0;
return sz; }
public int readbyte b[], int off, int len throws IOException { int sz = in.readb, off, len;
SockStreamLogger.reads, sz, b, off; return sz;
} public void reset throws IOException {in.reset ;}
public long skiplong n throws IOException {return in.skipn;} }
public class SockOutStreamLogger extends OutputStream {
Socket s; OutputStream out;
byte[] one_byte = new byte[1]; public SockOutStreamLoggerSocket so, OutputStream o{out = o; s = so;}
public void writeint b throws IOException { out.writeb;
one_byte[0] = byte b; SockStreamLogger.writtens, 1, one_byte, 0;
} public void writebyte b[] throws IOException {
out.writeb; SockStreamLogger.writtens, b.length, b, 0;
} public void writebyte b[], int off, int len throws IOException {
out.writeb, off, len; SockStreamLogger.writtens, len, b, off;
} public void flush throws IOException {out.flush ;}
public void close throws IOException {out.close ;} }
2.7 Performance Checklist
•
Use system- and network-level monitoring utilities to assist when measuring performance.
•
Run tests on unloaded systems with the test running in the foreground.
o
Use
System.currentTimeMillis
to get timestamps if you need to determine absolute times. Never use the timings obtained from a profiler as absolute times.
o
Account for all performance effects of any caches.
•
Get better profiling tools. The better your tools, the faster and more effective your tuning.
o
Pinpoint the bottlenecks in the application: with profilers, by instrumenting code putting in explicit timing statements, and by analyzing the code.
o
Target the top five to ten methods, and choose the quickest to fix.
o
Speed up the bottleneck methods that can be fixed the quickest.
o
Improve the method directly when the method takes a significant percentage of time and is not called too often.
o
Reduce the number of times a method is called when the method takes a significant percentage of time and is also called frequently.
•
Use an object-creation profiler together with garbage-collection statistics to determine which objects are created in large amounts and which large objects are created.
- 55 -
o
See if the garbage collector executes more often than you expect.
o
Use the
Runtime.totalMemory
and
Runtime.freeMemory
methods to monitor gross memory usage.
•
Check whether your communication layer has built-in tracing features.
o
Check whether your communication layer supports the addition of customized layers.
•
Identify the number of incoming and outgoing transfers and the amounts of data transferred in distributed applications.
Chapter 3. Underlying JDK Improvements
Throughout the progressive versions of Java, improvements have been made at all levels of the runtime system: in the garbage collector, in the code, in the VM handling of objects and threads,
and in compiler optimizations. It is always worthwhile to check your own application benchmarks against each version and each vendors version of the Java system you try out. Any differences in
performance need to be identified and explained; if you can determine that a compiler from one version or vendor together with the runtime from another version or vendor speeds up your
application, you may have the option of choosing the best of both worlds. Standard Java benchmarks tend to be of limited use in deciding which VMs provide the best performance for your
application. You are always better off creating your own application benchmark suite for deciding which VM and compiler best suit your application.
The following sections identify some points to consider as you investigate different VMs, compilers, and JDK classes. If you control the target Java runtime environment, i.e., with servlet
and other server applications, more options are available to you, and we will look at these extra options too.
3.1 Garbage Collection
The effects of the garbage collector can be difficult to determine accurately. It is worth including some tests in your performance benchmark suite that are specifically arranged to identify these
effects. You can do this only in a general way, since the garbage collector is not under your control. The basic way to see what the garbage collector is up to is to run with the
-verbosegc
option. This prints out time and space values for objects reclaimed and space recycled. The printout includes
explicit synchronous calls to the garbage collector using
System.gc
as well as asynchronous executions of the garbage collector, as occurs in normal operation when free memory available to
the VM gets low. You can try to force the VM to execute only synchronous garbage collections by using the
-noasyncgc
option to the Java executable no longer available from JDK 1.2. This option does not actually stop the garbage-collector thread from executing: it still executes if the VM
runs out of free memory as opposed to just getting low on memory. Output from the garbage collector running with
-verbosegc
is detailed in Section 2.2
. The garbage collector usually works by freeing the memory that becomes available from objects
that are no longer referenced or, if this does not free sufficient space, by expanding the available memory space by asking the operating system for more memory up to a maximum specified to the
VM with the
-Xmx -mx
option. The garbage collectors space-reclamation algorithm tends to change with each version of the JDK.