Pages

Friday, February 5, 2010

Java Performance Tips

Share it Please
Today's tip is about performance in Java. Here are a few things to watch out for. It is the little things that matter in the long run, so please pay attention:

1. Loops. Do not use nested loops as much as you can, unless you have to. Nested loops are VERY expensive.
2. For constant length number of items, use arrays instead of ArrayList. Only use ArrayList if you have a variable number of elements.
3. If you are using ArrayList, and you know you will have a lot of items in it, use the constructor that supplies an initial size for the ArrayList. If you don't supply that, Java creates an ArrayList of 10 items, and then recreate another ArrayList when the size is more than 10 items, and copies all the elements over from the first ArrayList to the new one. So, this is a very expensive operation. Try to start an ArrayList with a pre-size corresponding to the elements you already have, or start with a higher number. Just make sure you don't start with a number TOO HIGH because there is a penalty for that. If you start with a number like 20 and we only have 2 elements then 18 more spots have already been allocated in memory and it wastes space. So, if you get 25 objects back from Hibernate, and you want to put those elements in an ArrayList, then start with new ArrayList(25). DO NOT USE THIS TECHNIQUE WITH HASHMAPS. You should let them create themselves with their own size limitations and never enforce a size.
4. As much as you can create local variables inside methods or blocks. Every time you create a variable it lives until the { ends. So, if you want to create a variable in a class CalendarEntry and you are not sure whether to create it at the class level (static or instance variable), or to create it inside a method that will be using it, then choose the local variable inside the method. Only create variables at the class level if you really need to. The reason is the variable does not take up space until the method is called, and as soon as the method exits, the local variables dies. Saving us a space in memory.
5. Creating objects using the "new" keyword is very expensive in Java. So, try to reuse objects as much as you can. Especially in a loop. So, if you are declaring a temporary object such as Date or Calendar inside a loop just to do some calculations, then you may want to take the declaration outside the loop and reuse the same object over and over again. This will save so much.
6. Use StringBuilder if you are concatenating to a String (adding more strings to it using +) instead of String or StringBuffer.
7. Use Arrays class for sorting, searching, etc. as much as you can on an array of objects. And use Java's algorithms as much as you can because they are optimized for speed.
8. If a class needs to do heavy initialization of stuff, create static blocks just inside the class definition so those initializations get done at the class load level:

public class Test {

static{
//initialize some class level properties, etc.
}
...
}

9. Use paging and streaming as much as you can rather than loading ALL objects in an ArrayList or a Map. If you load all objects, they are all in memory taking too much space. If you are streaming to the client 10 objects at a time, or by using paging 10 at a time, then we are going to Hibernate to get the next set of objects as we need them. If the user does not click on the next page, then he only needed to see 10 not all 300 objects for example. Let's never load all objects from Hibernate in memory, and instead use Hibernate to get the next set of objects and consume them and only come back and get the next set when the user clicks next, etc.
10. If you have a bunch of boolean conditions in an IF statement for example, put the condition that is most likely to resolve to false most of the time in front. This will allow AND conditions (&&) to only evaluate the first condition and then exiting the loop if the first condition is false. The JVM will start evaluating the next condition ONLY if the previous condition is true. For example:

if (condition1 && condition2 && condition3)

In the statement above, if the first condition (condition1) is false, JVM exits this statement since it doesn't matter what conditions 2 and 3 are, since the first one is false and since we are using AND conditions, then there is no need to evaluate the rest. So, put the condition that is most likely to be false in the beginning to avoid having the JVM evaluate condition1, then condition2 then it finally finds out that condition3 is false.Do the exact same for OR statements (||) except put the most likely condition to be true in the beginning.

11. Static variables load faster than instance variables. So, if you have a variable that depends on the class and not individual instances, then make sure you declare it as static.
12. Use System.arraycopy() to copy arrays. In general, anything you want to do, or any algorithm, first look it up to see if Java does it, before you try to do it yourself because Java will do it the best.
13. For values that will hold numbers that are small use byte or short instead of int or long as much as possible. Only use int if the values can be more than what a short or byte can handle. Think in the future. So, if we have a constant number of value 5 or something like that then there is no need to create an int. Use a smaller value variable. The same for float and double. Check how much each of those variables can hold and make a proper analysis before using the correct type.
14. If you have a loop from n to m, it is faster to loop from m to n (the opposite) and decrementing the counter, rather than going from n to m and incrementing the counter. The reason is because our condition checks whether our counter has reached m. Since m > n, then checking on every cycle whether we have reached n (smaller number) is better than checking whether we have reached m (which is bigger number).
15. Make sure all transactions are closed at the end, and all connections are closed. Leaving connections open may cause a problem and running out of memory later.
16. Use lazy loading as much as you can. This means that unless the client needs it, don't load additional objects. So, if the user is viewing in daily view on the calendar, we don't need to send appointments for a different day than what we are viewing.
17. Use generics as much as you can.
18. Before being done with a class, always click the following in Eclipse "Shift + Alt + O", this will clean all import statements that are not needed and takes them out. Having more import statements for classes that you do not need will cause a hit at runtime forcing a loading of a class that you don't need.
19. Delcare methods that will not be inherited "final". This helps the compiler optimize code.
20. Avoid processing blocks of code if you don't need to. Sometimes you may need to move code inside a conditional statement to avoid having to execute it for cases that are not needed. For example, a Staff does not need to see all practices on the web site, so there is no need to have code load all practices on the server side, and then we don't send it to the client. Instead, we should NOT LOAD those practice objects in memory if the current user is staff since he will not to see them. So, be smart about when to call hibernate to load objects in memory. The fastest thing you can do is not load what is not needed, rather than loading them and not sending them to the client.
21. Use static final when creating constants.
22. Remove all System.out.println from production ready code. For testing it is fine, but not when it is ready to go to production.
23. Use annotations as much as you can because in Java 1.6 they are optimized for speed.
24.Replace strings and other objects with integer constants. Compare these integers by identity.
25.Avoid initializing instance variables more than once.
26.Use short-circuit boolean operators instead of the normal boolean operators. [ i+=1 is faster that i==i+1]
27.Use temporary local variables to manipulate data fields (instance/class variables).
28.String.equals() is expensive if you are only testing for an empty string. It is quicker to test if the length of the string is 0.
29.Avoid character processing using methods (e.g. charAt(), setCharAt()) inside a loop.
31.Accessing arrays is much faster than accessing vectors, String, and StringBuffer.
32.Perform the loop backwards (this actually performs slightly faster than forward loops do).
[Actually it is converting the test to compare against 0 that makes the difference].
33.Use only local variables inside a loop; assign class fields to local variables before the loop.
34.Shifting by powers of two is faster than multiplying.
35.Multiplication is faster than exponentiation.
36.increments are faster than byte or short increments.
37. Floating point increments are much slower than any integral increment.
38.Use -ms and -mx to tune the JVM heap. Bigger means more space but GC takes longer. Use the GC statistics to determine the optimal setting,
i.e the setting which provides the minimum average overhead from GC.
39.StringBuffer default size is 16 chars. Set this to the maximum expected string length.
40.Initialize expensive arrays in class static initializers, and create a per instance copy of this array initialized with System.arrarycopy().
41.Use charAt() instead of StartsWith() in case you are looking for a single character within a String.
42.Use the print() method rather than the println() method.
43.volatile fields can be slower than non-volatile fields, because the system is forced to store to memory rather than use registers. But they may useful to avoid concurrency problems.
44. One way to avoid creating objects simply for information is to provide finer-grained methods which return information as primitives. This swaps object creation for increased method calls.
45. A second technique to avoid creating objects is to provide methods which accept dummy information objects that have their state overwritten to pass the information.
46. A third technique to avoid creating objects is to provide immutable classes with mutable subclasses, by having state defined as protected in the superclass, but with no public updators. The subclass provides public updators, hence making it mutable.

A few Hiberante Performance Tips ,

1 - Composite keys must always be mapped only by identifiers, not associations, because when you map an association to a primary key, everytime that you execute a session.find on this object, all the associations defined at composite key will be eagerly loaded.
2 - Always provide a reasonable BatchSize
3 - Always use Hibernate.initialize(property) before trying to access the lazy properties.
4 - Always prefer to use the session.merge mechanism instead of session.save, session.update or session.saveOrUpdate, to prevent abnormal use of session (like the infamous NonUniqueObjectException).
5 - Provide acess to the hibernate API on the Data Access Layer, to provide extensibility on the points that hibernate has poor or no available resource (like providing named queries, native queries, stored procedures executions, updating lock modes on the fly and using the evict and initialize features.
6 - Always prefer to use named queries instead of string parsed queries, for cache reasons, and to prevent HQL injection
7 - Always prefer to use HibernateCallback in conjunction with the hibernateTemplate.
8 - Using the right Collection for the right association needed (Set if you have to provide a collection without duplications, List if you can have duplicity, Map if you have to provide key/value pairs).
9 - Using the HQL correctly to load only what is needed - excluding all unused data to be performant.
10 - Use @Cache on class level and on association level.

Happy Coding...

1 comment :

  1. Awesome tips , really useful for all the people who want to become java programmer .

    ReplyDelete