java performance
DESCRIPTION
Java Performance notes. Subtle changes that could make a difference. Generally interesting concepts (I hope), food for thought/ for debate.TRANSCRIPT
Jan 2010 Java Performance Quest for Speed
Rajesuwer P Singaravelu
Discussed here are subtle changes that could make a difference. Minor gains, of say 2ms, could be significant if you are performing 100K operations to serve a request. Architectural patterns are not considered here.
Introduction
Introduction - Know Your Application
Different applications have different performance characteristics and bottlenecks.
Performance varies across different hardware, operating systems, compilers and virtual machines.
Performance - Cousins
Equally important are:
Code Quality
Maintainability
Readability
Performance - Architecture
Poor performance built into your app?
Heavy use of the object-oriented paradigm (many layers of superclasses and subclasses)
Simple tuning won’t do. Re-design application or parts of it.
Keep performance in mind when designing your applications.
Performance - Algorithm
Use efficient algorithms.
Do you use O(n2) bubblesort algorithm or a much more efficient O(n log n) quicksort ?
Tech Tips
Avoid Creating Objects
Object creation is never free. This has gotten better over years, but allocating memory is always more expensive than not allocating memory.
Reuse objects where possible.
Short Circuit
Perform a cheap test before an expensive one
if (s1 == s2 || s1.equals(s2))
Wrappers
Wrapper classes come with overhead- time and space
Watch out for autoboxing
Consider Efficient Alternatives:If you need to add int-s to a list or map, consider using TIntArrayList, TIntObjectHashMap and such from trove library.
Prefer Concrete Over Interface
Suppose you have a HashMap object. You can declare it as a HashMap or as a generic Map:
Map myMap1 = new HashMap() vs HashMap myMap2 = new HashMap()
Which is better?
Calling through an interface reference can take longer than a call through a concrete reference.
If you have chosen a HashMap because it fits what you're doing, there is little value in calling it a Map. Given the availability of IDEs that refactor your code for you, there's not much value in calling it a Map even if you're not sure where the code is headed. (Again, though, public APIs are an exception: a good API usually trumps small performance concerns.)
Prefer Static Over Virtual
Make methods staticIf you don’t need access to object’s fields
Can be fasterDoesn't require a virtual method table indirection, so can be faster.
Also good practiceMethod signature conveys that calling the method can’t/doesn’t alter the object's state.
(Avoid) Internal Getters/Setters
Use
i = this.var
Instead of
i = getVar()
Especially inside loops.
Which is expensive- method call or instance variable lookup?
Cache Field Lookups
Accessing object fields is much slower than accessing local variables.
Instead of:
for (int i=0; i<this.mCount; i++) dumpItem(this.mItems[i]);
Write:
int count = this.mCount; Item[] items = this.mItems; for (int i = 0; i < count; i++) dumpItems(items[i]);
Enhanced For Loop - Use Caution
For ArrayList, use:
for(int i=0; i < count; i++){ list.get(i); }
instead of:
for(String s: list){ .. }
For other collections the “for-each” loop will be equivalent to explicit iterator usage.
Synchronization
Avoid synchronized methods if you can.
If you can't, synchronizing on methods rather than on code blocks is slightly faster.
Exception
Use exceptions where you really need them.
Have a high basic cost, & their presence can hurt compiler analysis.
Using API classes
Use Java API classes when they offer native machine performance that you can't match using Java.
For example, arraycopy() is much faster than using a loop to copy an array of any significant size.
Avoid expensive constructs
Sometimes Java constructs are so expensive that it can be worth making your data structures or code a little more complex to work around the problem.
For example, you can add a type id number to objects to avoid paying the cost of an instanceof (this also allows you to use the result in a switch).
Similarly, in a long inheritance tree you can avoid casting by including a method that returns a value of the type you would otherwise cast to.
Avoid expensive data structures
Expensive Java data structures can be replaced with simpler ones at the cost of some extra code complexity.
For example, it can be up to twice as expensive to access a two-dimensional array as a one-dimensional array, due to the extra indirections.
Know your switches
When the numbers are close together, uses a fast direct lookup.
When the numbers are further apart, uses a slower search through a table.
This is particularly important if you're trying to replace a sequence of ‘if’ statements with a switch.
Method inlining
The Java 2 VM automatically inlines simple methods at runtime.
Make a method look attractive to the VM to inline (e.g.: no return value) or manually inline a method if it doesn't break your object model.
Enums
Enums are very convenient, but unfortunately can be painful when size and speed matter.
On first use, the class initializer invokes the <init> method on objects representing each of the enumerated values.
Each object gets its own static field, and the full set is stored in an array (a static field called "$VALUES").
That's a lot of code and data, just for three integers.
Use Package Scope with Inner Classes
Inner class is a totally separate class (behind the scenes).
To make direct access to parent class’ private members, the compiler generates a couple of synthetic methods.
The inner-class code calls these static methods whenever it needs to access the private members of enclosing class.
Translation: members accessed through accessor methods instead of directly. (accessors are slower than direct field accesses)
Remedy: declare members accessed by inner classes to have package scope, rather than private scope.
Flip-side: other classes in the same package can access too; runs counter to the standard OO practice.
Replacing API classes
Sometimes API classes do more than you need -with a corresponding increase in execution time
You can write specialized versions that do less but run faster.
Overriding API methods
Performance problems with a Java API method?
Define a subclass, override that method with your own (hopefully more efficient) version.
Strength Reduction
Use cheaper operations in place of expensive ones.
‣ += instead of ...=...+... result in fewer byte code instructions.
‣ Make a 1D array variable that points to the row, if repeatedly accessing elements in a single row of a 2D array
‣ Shifts instead of multiplication by powers of two
‣ Multiplication instead of exponentiation, etc.
/ mathematical optimizations of this type generally have little benefit unless you are using a just-in-time compiler /
Variable allocation
For desperate optimizers only.
The first four numeric variables or arguments in a method are accessed using via shorter bytecode instructions, although only three are usable in non-static methods.
If you declare your most frequently-used variables first (e.g., loop indices), the inner bytecode loops of your methods will be marginally shorter and possibly faster. Note that although the number of bytecodes for the inner loop is the same, the length of the bytecode has decreased.
Common subexpression elimination
If an expensive expression (for example, the result of a method call) is used more than once within a block of code, calculate it once and put it into a temporary variable for subsequent reuse.
double d = a * Math.sqrt(c); double tmp = Math.sqrt(c);
double e = b * Math.sqrt(c); double d = a * tmp;
double e = b * tmp;
Loop invariant code motion
If an expression inside a loop doesn't change after the loop is entered (i.e. it's invariant), calculate the value of the expression outside the loop and assign it to a temporary variable. Then use the temporary variable within the loop.
Note that we could also treat array.length as a loop invariant.
Use the right algorithms & data structures
Don't use an O(n2) bubblesort algorithm to sort a thousand elements when there's an O(n log n) quicksort available.
Similarly, don't store a thousand items in an array that requires an O(n) search when you could use an O(log n) binary tree, or an O(1) Java hash table.
Wholesale is Cheaper
Perform operations in bulk instead of one at a time.
DB access in loop: Optimize SQL to perform in one bulk access (not same as executeBatch() )
Closing Notes
To write good, efficient code:Understand what the code you write really does.
Make deliberate choice, not inadvertent side effect:If you really want to allocate an iterator, by all means use enhanced for loop syntax on a List; just make it a deliberate choice.
Build performance into your application; then make it better.
Always think carefully about what your code is doing, and be on the lookout for ways to speed it up.
quest for speed continues...