Use system- and network-level monitoring utilities to assist when measuring performance.
Run tests on unloaded systems with the test running in the foreground.
Use System.currentTimeMillis( ) to get timestamps if you need to determine absolute times. Never use the timings obtained from a profiler as absolute times.
Account for performance effects of any caches.
Get better profiling tools. The better your tools, the faster and more effective your tuning.
Pinpoint the bottlenecks in the application: with profilers, by instrumenting code (putting in explicit timing statements), and by analyzing the code.
Target the top five to ten methods, and choose the quickest to fix.
Speed up the bottleneck methods that can be fixed the quickest.
Improve the method directly when the method takes a significant percentage of time and is not called too often.
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 numbers and which large objects are created.
See if the garbage collector executes more often than you expect.
Determine the percentage of time spent in garbage collection and reduce that if over 15% (target 5% ideally).
Use the Runtime.totalMemory( ) and Runtime.freeMemory( ) methods to monitor gross memory usage.
Check whether your communication layer has built-in tracing features.
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.