Tuning Java Code
Tuning Java Code
Performance Issues
Performance Issues
System Interactions Database Other Server Component Framework Web Client Connection User
Performance Issues
Performance Issues
Performance Issues
System Interactions Component Framework EJB Container Session Facade pattern to control transaction
and remote method granularity
Performance Issues
System Interactions Web Client Connection DHTML to reduce page loads User Javascript to pre-validate data
Performance Issues
Algorithms Linear Search Tree, Hash Table java.util Collections Application Specic Collections
Code Tuning
Prole to nd Hot Spots 90/10 Rule 90% of time spent in 10% of code Concentrate tuning on hot spots identied by
the proler.
Example Application
Business Rules Engine HaleyRules for Java Platform Haley Systems, Inc. http://www.haley.com/
Initial benchmark: > 10x slower than C Proler results: 80% of time spent in one area: Object creation / collection
Reduce
static String append(String[] array) { String result = ""; for (int i = 0; i < array.length; i++) { result = result + array[i]; } return result; } The above code creates at least array.length * 3 objects. Each pass of the loop creates a StringBuffer (for the append operation), at least one array for the StringBuffer, and a String for the new value of result. We can do better with: static String append(String[] array) { StringBuffer result = new StringBuffer(); for (int i = 0; i < array.length; i++) { result.append(array[i]); } return result.toString(); }
Reuse
StringBuffer sb = new StringBuffer(); . . . sb.setLength(0); . . . sb.setLength(0);
Reuse
double d; java.io.Writer writer; writer.write(Double.toString(d));
import java.io.*; import java.text.*; public class NumberWriter extends FilterWriter { private StringBuffer stringBuffer = new StringBuffer(); private char[] chars = new char[64]; private NumberFormat realFormat = NumberFormat.getInstance(); private FieldPosition integerField = new FieldPosition(NumberFormat.INTEGER_FIELD); NumberWriter(Writer writer) { super(writer); } public void write(double value) throws IOException { stringBuffer.setLength(0); realFormat.format(value, stringBuffer, integerField); writeStringBuffer(); } private void writeStringBuffer() throws IOException { int size = stringBuffer.length(); stringBuffer.getChars(0, size, chars, 0); write(chars, 0, size); } }
class Complex { double real, imaginary; Complex() {} Complex(double real, double imaginary) { this.real = real; this.imaginary = imaginary; } final static Complex add(Complex c1, Complex c2) { Complex result = new Complex(); result.real = c1.real + c2.real; result.imaginary = c1.imaginary + c2.imaginary; return result; } } static Complex sum(Complex[] array) { Complex result = new Complex(0, 0); for (int i = 0; i < array.length; i++) { result = Complex.add(result, array[i]); } return result; }
330 microseconds
Proling
http://javalinux.rallylobster.com/
CDROM/Chapter60/PerfAnal/
http://java.sun.com/developer/
technicalArticles/Programming/ perfanal/
final static Complex add(Complex c1, Complex c2) { Complex result = new Complex();
Reuse
final static void add(Complex c1, Complex c2, Complex result) { result.real = c1.real + c2.real; result.imaginary = c1.imaginary + c2.imaginary; } static Complex sum1(Complex[] array) { Complex result = new Complex(0, 0); for (int i = 0; i < array.length; i++) { Complex.add(result, array[i], result); } return result; }
54 microseconds
The Java language specication allows the compiler/JVM to perform this type of optimization automatically. However, as of JDK 1.4.2, Suns implementation does not perform this optimization. Caching values in local variables can therefore produce a signicant improvement (almost a factor of 2 in this example).
Reuse
Note: some J2EE practitioners use Value Object as the term for what other OO designers were already calling Data Transfer Object. See Patterns of Enterprise Application Architecture, Martin Fowler, page 486.
Reuse
Flyweight Pattern
Flyweight Pattern
public class IntegerFactory { private static final int MIN_CACHED = -10; private static final int MAX_CACHED = 100; private static Integer cached[]; static { cached = new Integer[MAX_CACHED-MIN_CACHED+1]; for (int i = MIN_CACHED; i <= MAX_CACHED; i++) { cached[i-MIN_CACHED] = new Integer(i); } } public static Integer getInteger(int i) { if (i >= MIN_CACHED && i <= MAX_CACHED) { return cached[i-MIN_CACHED]; } else { return new Integer(i); } } }
Flyweight Pattern
Java 5.0 added static valueOf methods for classes in java.lang that wrap primitive types. valueOf methods are used for automatic boxing of primitive types when passed to methods that expect objects. Boolean, Char, Byte, Short, Int, and Long use the yweight pattern in valueOf.
public static Integer valueOf(int i) { final int offset = 128; if (i >= -128 && i <= 127) { // must cache return IntegerCache.cache[i + offset]; } return new Integer(i); }
Recycle
class ObjectPool { private Class objectClass; // Class of objects managed by this factory PooledObject freeObjects; // List of previously used objects public ObjectPool(Class objectClass) {this.objectClass = objectClass; } public PooledObject get() throws InstantiationException, IllegalAccessException { PooledObject pooledObject = null; if (freeObjects == null) { pooledObject // Allocate a new object = (PooledObject) objectClass.newInstance(); } else { pooledObject = freeObjects; // Get an existing object from the free list freeObjects = freeObjects.nextFree; } pooledObject.factory = this; pooledObject.nextFree = null; return pooledObject; } } abstract class PooledObject { PooledObject nextFree; // Next object on free list ObjectPool factory; void free() { nextFree = factory.freeList; // Add object to free list factory.freeList = this; } }
Recycle
Issues with object pooling Increased memory usage Lack of automatic object initialization Threading issues Per-thread object pools minimize
Reection
Used to implement languages, extensible systems Two steps: Use class and method names to lookup class and
method at runtime
java.lang.reflect.Method.invoke()
Reection
static void test() {} 2.7 GHz Intel Celeron All times are in nanoseconds
Windows XP 1.3.1
Direct call Cached java.util.Method Lookup every call
7 814 13377
Reection Recommendations
Avoid reection if possible Dene interfaces for extension classes Automatic code generation Do lookups once and cache
java.lang.reflect.Method object
Exceptions
try { throw new Exception("An error occurred"); } catch (Exception e) {} 12.8 microseconds try { throw cachedException; } catch (Exception e) {} 1.2 microseconds
Exception.printStackTrace()
Casts
Minimize casts. Cast once and store in local variable. Cost depends on depth of type hierarchy. Interfaces are more expensive. Recent JVMs are better. Dont change design for minor performance gains. Java 5.0 generics eliminate casts from source code,
but not from generated bytecode.
Quotes
Donald Knuth We should forget about small efciencies, say about 97% of the time. Premature optimization is the root of all evil. M. A. Jackson Rules of Optimization: Rule 1: Dont do it. Rule 2: (for experts only) Dont do it yet. William A. Wulf More computing sins are committed in the name of efciency (without necessarily achieving it) than for any other single reason - including blind stupidity. Jon Bentley On the other hand, we cannot ignore efciency.
Resources
Java Performance Tuning Jack Shirazi http://www.oreilly.com/catalog/javapt2/ Effective Java Programming Language Guide Joshua Bloch http://java.sun.com/docs/books/effective/ Better, Faster, Lighter Java Bruce A.Tate, JustinGehtland http://www.oreilly.com/catalog/bjava/