43

There are number of performance tips made obsolete by Java compiler and especially Profile-guided optimization. For example, these platform-provided optimizations can drastically (according to sources) reduces the cost of virtual function calls. VM is also capable of method inlining, loop unrolling etc.

What are other performance optimization techniques you came around still being applied but are actually made obsolete by optimization mechanisms found in more modern JVMs?

Dan
  • 11,077
  • 20
  • 84
  • 119

8 Answers8

24

The final modifier on methods and method parameters doesn't help with the performance at all.

Also, the Java HotSpot wiki gives a good overview of the optimizations used by HotSpot and how to efficiently use them in Java code.

Mat Gessel
  • 562
  • 8
  • 17
Eugene Kuleshov
  • 31,461
  • 5
  • 66
  • 67
  • 2
    nice link, but it doesn't seem to dismiss `final`. It says that 'final' is a hint to inlining. I thought there were cases where final modifier will assure the compiler that its value cannot change in a loop even if that loop invokes other methods and beyond the current horizon. – Will Oct 25 '10 at 22:07
  • See: http://stackoverflow.com/questions/3961881/why-defining-class-as-final-improves-jvm-performance – andersoj Oct 26 '10 at 01:00
  • 4
    `final` on methods (or classes for that matter) provides no information to the JIT. However, `final` on a method parameter could very well provide useful optimizing hints (similar to a local variable declared as final). Ultimately, though, the reason to use final is to force immutability - this is a design-time characteristic to make code easier to maintain. Any optimization benefit would need to be a) only worried about if there was actually a performance problem, and b) tested exhaustively to ensure that it actually made a difference. – Kevin Day Oct 26 '10 at 03:55
  • 2
    Actually, `final` on a parameter will normally make no difference at all (the compiler really can see whether or not you assign to it and Java doesn't pass variables by reference – objects go by reference, but the variable holding them doesn't) *but* it does mean that the parameter can be used with an inner class or anonymous class. Use if meaningful for that, otherwise don't. – Donal Fellows Nov 16 '10 at 14:54
  • 4
    I use final as a way to ensure immutability of a class. Generally as private final fields. I also use it to ensure that I do not change the values/references of passed parameters. In other words, I just use it for correctness rather than optimization. – Archimedes Trajano Nov 18 '10 at 01:55
  • 6
    I don't use final on a method parameter or method variables to optimise anything, I use it as coding practice so fellow developers can see that this value really does not change. Any optimisation is second to that. – Richard Nov 18 '10 at 18:13
21

People replacing String a = "this" + var1 + " is " + var2; with multiple calls to StringBuilder or StringBuffer. It actually already uses StringBuilder behind the scenes.

Paul Tomblin
  • 179,021
  • 58
  • 319
  • 408
  • In this case, I believe the optimization still applies. The sample code you showed would construct 3 distinct StringBuilder instances, one for each concatenation; constructing only one would be (slightly) more efficient. Correct me if I am wrong. – RMorrisey Oct 25 '10 at 21:57
  • 3
    Oh, I thought it would do the equivalent of `String a = new StringBuilder("this").append(var1).append("is").append(var2).toString();`? – Paul Tomblin Oct 25 '10 at 22:00
  • 3
    this *unauthoriative* source http://www.rgagnon.com/javadetails/java-0129.html suggests Paul is right regards the single StringBuilder, but says the default capacity of the StringBuilder can be too short (strange, it would be trivial for a compiler that took the time to use a StringBuffer would not bother to count the capacity before use) – Will Oct 25 '10 at 22:12
  • Using StringBuffer will even slow down the code as it involves synchronization. In a application making an heavy unnecessary use of StringBuffer, I replaced all occurrences by StringBuilder and got a 10% latency improvement. – Guillaume Nov 15 '10 at 16:51
  • 3
    When string concatenation is done on one line, using StrinBuilder adds nothing. However, replacing this: `String a = "this" + var1; a += " is " + var2;` with StringBuilder is still effective. (At least it was last time I checked :-/) – Devon_C_Miller Nov 16 '10 at 15:38
  • 2
    @Devon, I would think you're right, because doing it on multiple lines would involve creating a bunch of different String objects. – Paul Tomblin Nov 16 '10 at 15:59
  • And in the end of the day "Who gives a bloody darn if this was *optimized* or not?" (Consider, well, 99% of use-cases.) –  Nov 19 '10 at 19:35
  • http://stackoverflow.com/questions/22241841/huge-xml-file-to-text-files/22244296#22244296 is an example where replacing a `+=` in a loop with a single `StringBuilder` greatly affected performance; in that case execution time was reduced from 35 minutes to 6 minutes. – Jason C Mar 16 '14 at 20:12
  • If you're doing it thousands of times in a loop, yes, it's a worthwhile optimization, but the example in my answer is not going to save you a measurable amount. – Paul Tomblin Mar 17 '14 at 12:52
17

It is necessary to define time/memory trade-offs before starting the performance optimization. This is how I do it for my memory/time critical application (repeating some answers above, to be complete):

  1. Rule #1 Never do performance optimization on the earlier stage of development. Never do it if your don't need it really. If decided to do it, then:
  2. use profiler to find bottlenecks, review the source code to find the reasons for bottlenecks;
  3. choose appropriate data structure with the best fit into the defined time/memory trade-offs;
  4. choose appropriate algorithms (e.g. iteration vs recursion, etc);
  5. avoid using synchronized objects from java library, if you don't need it really;
  6. avoid explicitly/implicitly new object creation;
  7. override/re-implement data types/algorithms coming with the java if and only if you are sure they doesn't fit your requirements.
  8. Use small, independent tests to test the performance of chosen algos/data structures.
khachik
  • 28,112
  • 9
  • 59
  • 94
  • 2
    These tips aren't really obselete. I mean, it's brilliant advise, but you're not answering the question. – Charles Goodwin Sep 15 '11 at 00:58
  • To mitigate rule 1, there are things that are easy to write and easy to read, that any decent software engineer should know and do correctly right away, such as choosing between a linked list and an array list. That comes for free and avoids headaches later. That is, good software design, in essence. – coffee_machine Mar 04 '19 at 08:56
8

In 2001 I made apps for a J2ME phone. It was the size of a brick. And very nearly the computational power of a brick.

Making Java apps run acceptably on it required writing them in as procedural fashion as possible. Furthermore, the very large performance improvement was to catch the ArrayIndexOutOfBoundsException to exit for-loops over all items in a vector. Think about that!

Even on Android there are 'fast' loops through all items in an array and 'slow' ways of writing the same thing, as mentioned in the Google IO videos on dalvik VM internals.

However, in answer to your question, I would say that it is most unusual to have to micro-optimise this kind of thing these days, and I'd further expect that on a JIT VM (even the new Android 2.2 VM, which adds JIT) these optimisations are moot. In 2001 the phone ran KVM interpreter at 33MHz. Now it runs dalvik - a much faster VM than KVM - at 500MHz to 1500MHz, with a much faster ARM architecture (better processor even allowing for clock speed gains) with L1 e.t.c. and JIT arrives.

We are not yet in the realms where I'd be comfortable doing direct pixel manipulation in Java - either on-phone or on the desktop with an i7 - so there are still normal every-day code that Java isn't fast enough for. Here's an interesting blog that claims an expert has said that Java is 80% of C++ speed for some heavy CPU task; I am sceptical, I write image manipulation code and I see an order of magnitude between Java and native for loops over pixels. Maybe I'm missing some trick...? :D

Donal Fellows
  • 133,037
  • 18
  • 149
  • 215
Will
  • 73,905
  • 40
  • 169
  • 246
  • 1
    A bit OT, but in regards to performance, a friend of mine has created a source-faithful Doom port in Java, and it gets about 130-145 FPS at 640x480 resolution on a single threaded P4 @ 3GHz. Not OpenGL, just blitting. – Tassos Bassoukos Nov 15 '10 at 17:28
  • Yeah, but I played Doom acceptably on a 486... (however, your friend's project sounds a lot of fun and very cool) – Will Nov 16 '10 at 15:40
4
  1. Don't manually call the garbage collector, it hurts performance on modern JVM implementations.
  2. Integer instead of Long will not save much space, but will limit the range of the numbers.
  3. Avoid hand generated Enum classes and use the built in Enum instead. Java 1.5 introduced real Enums, use them.
Michael Shopsin
  • 2,055
  • 2
  • 24
  • 43
2

When using x64 JVM with RAM less than 32GB:

64bit JVM use 30%-50% more memory in comparision to 32bit JVM because of bigger ordinary object pointers. You can heavily reduce this factor by using JDK6+.

From JDK6u6p to JDK6u22 it is optional and can be enabled by adding JVM argument:

-XX:+UseCompressedOops 

From JDK6u23 (JDK7 also) it is enabled by default. More info here.

Waldemar Wosiński
  • 1,490
  • 17
  • 28
1
  1. "Premature optimization is the root of all evil"(Donald Knuth)
  2. It is useful to optimize only the bottlenecks.
  3. You should analyze the code in each situation. Maybe you can replace the TreeSet by a fast HashSet because you don't need the sorting feature or maybe you can use float instead of double( look at the Android SDK).
  4. If no technique helps you can try to rewrite a piece of code and call it via JNI, so that native code is working.
keyser
  • 18,829
  • 16
  • 59
  • 101
Vladimir Ivanov
  • 42,730
  • 18
  • 77
  • 103
  • 7
    -1 for the quote that is both incomplete and also not relevant to the question. Donald Knuth said "We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil" Secondly the question is about general optimisation techniques that are no longer applicable, there is nothing to demonstrate that it is premature, it's a general discussion – hhafez Nov 21 '10 at 09:51
0

I found links above outdated. Here is a new one on Java optimization: http://www.appperfect.com/support/java-coding-rules/optimization.html

Zon
  • 18,610
  • 7
  • 91
  • 99