Thursday, August 30, 2012

Java Performance Tips

Every little things add up. The overall performance of an application depends on the individual performance of its components. Here we list some of the Java programming tips to help your application perform:

Programming Tips Why and How
Avoid creating duplicate objects Why:
  • Less objects less GC.
  • Application with smaller footprint performs better.
How:
  • Reuse a single object instead of creating a new functionally equivalent object each time it's needed.
    • (Do)
      • String s = "No longer silly";
    • (Don't)
      • String s = new String("silly");
  • Use static factory methods in preference to constructors on immutable classes that provide both.
  • Reuse mutable objects that are never modified once their values have been computed (within a static initializer).
Avoid circular references Why:
  • Groups of mutually referencing objects which are not directly referenced by other objects and are unreachable can thus become permanently resident.
How:
  • You can use strong references for "parent-to-child" references, and weak references for "child-to-parent" references, thus avoiding cycles.
Caching frequently-used data or objects Why:
  • One of the canonical performance-related use cases for Java is to supply a middle tier that caches data from back-end database resources.
    • (Warning) Like all cases where objects are reused, there is a potential performance downside: if the cache consumes too much memory, it will cause GC pressure.
How:
  • Code should use a PreparedStatement rather than a Statement for its JDBC calls.
  • Reuse JDBC connections because connections to a database are time-consuming to create.
Use the == operator instead of the equals(Object) method Why:
  • == operator performs better.
    • For example, for String comparison, the equals( ) method compares the characters inside a String object. The == operator compares two object references to see whether they refer to the same instance.
How:
  • a.equals(b) if and only if a == b
    • For example, use static factory method to return the same object from repeated invocations.
Eliminate obsolete object references Why:
  • Reduced performance with more garbage collector activity
  • Reduced performance with increased memory footprint
How:
  • Null out references once they become obsolete
  • (Do)
    • public Object pop() {
       if (size == 0)
         throw new EmptyStackException(;
       Object result = elements[--size];
       elements[size] == null;  // Eliminate obsolete reference
       return result;
      }
  • (Don't)
    • public Object pop(){
       if (size == 0)
         throw new EmptyStackException(;
       return elements[--size];
      }
Avoid finalizers Why:
  • Objects waiting for fnalization have to be kept track of separately by the garbage collector. 
  • There is also call overhead when the finalize method is invoked
  • Finalizers are unsafe in that they can resurrect objects and interfere with the GC.

Avoid reference objects Why:

  • As with fnalizers, the garbage collector has to treat soft, weak, and phantom references specially. 
  • Although all of these can provide great aid in, for example, simplifying a cache implementation, too many live Reference objects will make the garbage collector run slower. 
  • A Reference object is usually a magnitude more expensive than a normal object (strong reference) to bookkeep.
  • To find out the number of references and the time it takes to process them in HotSpot, add the following JVM option:
    • -XX:+PrintReferenceGC
Avoid object pooling Why:
  • Object pooling contributes both to more live data and to longer object life spans.
  • Note that large amounts of live data is a GC bottleneck and the GC is optimized to handle many objects with short life spans.
  • Also, allocating fresh objects instead of keeping old objects alive, will most likely  be more beneficial to cache locality.
  • However, performance in an environment with many large objects, for example large arrays, may occasionally benefit from object pooling.
Choose good algorithms and data structures Why:
  • Consider a queue implementation in the form of a linked list.
    • Even if your program never iterates over the entire linked list, the garbage collector still has to.
    • Bad cache locality can ensue because payloads or element wrappers aren't guaranteed to be stored next to each other in memory. This will cause long pause times as, if the object pointers are spread over a very large heap area, a garbage collector would repeatedly miss the cache while doing pointer chasing during its mark phase.
Avoid System.gc  Why:
  • There is no guarantee from the Java language specifcation that calling System.gc will do anything at all. But if it does, it probably does more than you want or doesn't do the same thing every time you call it. 
Avoid too many threads Why:
  • The number of context switches grows proportionally to the number of fairly scheduled threads, and there may also be hidden overhead here.
    • For example, a native thread context on a system such as Intel IA-64 processor is on the order of several KB.
Avoid contented locks Why:
  • Contended locks are bottlenecks, as their presence means that several threads want to access the same resource or execute the same piece of code at the same time. 
Avoid unnecessary exceptions Why:
  • Handling exceptions takes time and interrupts normal program flow. 
  • Authors[1] have seen cases with customer applications throwing tens of thousands of unnecessary NullPointerExceptions every second, as part of normal control fow. Once this behavior was rectifed, performance gains of an order of magnitude were achieved.

Avoid large objects Why:
  • Large objects sometimes have to be allocated directly on the heap and not in thread local areas (TLA).
    • Large objects on the heap are bad in that they contribute to fragmentation more quickly.
  • Large object allocation in VMs (for example, in JRockit) also contributes to overhead because it may require taking a global heap lock on allocation.
  • An overuse of large objects leads to full heap compaction being done too frequently, which is very disruptive and requires stopping the world for large amounts of time.


Tuning Guidelines


As stated in [6], here are the guidelines for tuning your applications:
You should take an overall system approach to ensure that you cover all facets of the environment in which the application runs. The overall system approach begins with the external environment and continues drilling down into all parts of the system and application. Taking a broad approach and tuning the overall environment ensures that the application will perform well and that system performance can meet all of your requirements.

References

  1. Oracle JRockit
  2. Effective Java by Joshua Bloch
  3. hashCode() and equals() in Java
  4. HotSpot VM Performance Tuning Tips
  5. Java Performance by Charlie Hunt, Binu John, David Dagastine
  6. Professional Oracle WebLogic Server by Robert Patrick, Gregory Nyberg, and Philip Aston
  7. Sun Performance and Tuning: Java and the Internet by Adrian Cockroft and Richard Pettit
  8. Concurrent Programming in Java: Design Principles and Patterns by Doug Lea
  9. Capacity Planning for Web Performance: Metrics, Models, and Methods by Daniel A. MenascĂ© and Virgilio A.F. Almeida
  10. Big-O complexities of common algorithms (Cheat Sheet)


1 comment:

Blogger said...

If you want your ex-girlfriend or ex-boyfriend to come crawling back to you on their knees (no matter why you broke up) you got to watch this video
right away...

(VIDEO) Have your ex CRAWLING back to you...?