Peter is a DZone MVB and is not an employee of DZone and has posted 161 posts at DZone. You can read more from them at their website. View Full User Profile

DZone Top Articles of 2011: How to get C like performance in Java

01.04.2012
| 21127 views |
  • submit to reddit

This article was selected as one of DZone's most popular, high-quality posts of 2011.  It is now republished as part of a series that will revisit the top articles of 2011 throughout the month of January 2012. 

Overview

Java has many areas which can be slow. However for every problem there is a solution. Many solutions/hacks require working around Java's protections but if you need low level performance it is still possible.

Java makes high level programming simpler and easier at the cost of making low level programming much harder. Fortunately most applications follow the rule of thumb that you spend 90% of your time in 10% of the code. This implies you are better off 90% of the time, worse off 10% of the time. ;)

It makes me wonder why you would write more than 10% of your code in C/C++ for most projects. There will be some projects where C/C++ is the only sensible solution, but I suspect most C/C++ projects would more productive with the use of higher level languages like Java.

One way to get C-like performance is to use C via JNI for key sections of code. If you want to avoid using C or JNI there are still ways you can get the performance you want.

Note: Most of these suggestions only work for standalone applications rather than applets.

Note 2: Use at your own risk. You are likely to need to test edge cases which you wouldn't normally need to worry about when using low level Java.

Fast array access

One area Java can be slower is array access. This is because it implicitly does bounds checking. The JVM is smart enough to optimise checks for loops by checking the first and last element, however this doesn't always apply.

One work around is to use the Unsafe class (which is only available on some JVMs, OpenJDK JVMs do) This class has getXxxx() and setXxxx() for each primitive type and gives you direct access to an object, array or direct memory where you have to do the bounds checking. In native code, these are compiled to single machine code instruction. There is also a getObject(), setObject() methods however I suspect that they don't provide as much of a performance improvement (by the time you access the Object as well)

You can check the native code generated for a method by downloading the debug version of the OpenJDK and getting it to print the compiled native code.

Arbitrary memory access

You can use the Unsafe class again for arbitrary access, however a "friendlier" way is to use a DirectByteBuffer and change its address and limit as desired (via reflection or via JNI) This will give you a Buffer which points to a random area of memory such as device buffer.

Using less memory

This is not as much of an issue as it used to be. A 16 GB server costs $1000 and a 1 TB server costs about $70K.

However, cache memory is still a premium and for some applications and its worth cutting memory consumption. A simple thing to do is to use Trove which support primitives in collections efficiently. If you have a large table of data, you can store data by column instead of by row (if you have lots of rows of data, and a few columns). This can improve caching behaviour if you are scanning data by field but don't need all fields.

You can also use Direct memory to store data how you wish. This is what the BigMemory library uses.

Stream based IO is slow and NIO is a pain to use

How can use you have the best of both worlds? Use blocking IO in NIO (which is the default for a Channel) Don't use Selectors unless you need them. In many cases, they just add complexity. Most systems can handle 1K-10K threads efficiently. If you need more connections than that, buy another server, a cheap one cost about $500.

Fast Efficient Strings

Java 6 update 21 has an option -XX:+UseCompressedStrings which can use byte[] instead of char[] for the strings which don't need 16-bit characters. For many applications this saves memory but is slower. (5%-10%)

Instead you can use your own Text type which wraps a byte[], or get you text data from ByteBuffer, CharBuffer or use Unsafe.

Faster Startup times

Java tends to have slow startup times when you load in lots of bloated libraries. If this is really a problem for you load less libraries. Keeping them to a minimum is good practice anyway. Do this and your startup times will be a few seconds (not as fast as C, but likely to be fast enough)

Less GC pauses

Most Java libraries create objects freely and generally this is not a problem.

However this doesn't mean you can't pre-allocate your objects, use Direct ByteBuffers and Object recycling techniques to minimise your object creation. By increasing the Eden size you can have an application which rarely GCs. You may even reduce it to one GC per day (say as a scheduled over night job)

Source:  http://vanillajava.blogspot.com/2011/05/how-to-get-c-like-performance-in-java.html
Published at DZone with permission of Peter Lawrey, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Tags:

Comments

Bruce Fancher replied on Wed, 2011/07/20 - 1:07pm

You mean "Fewer GC pauses", not "Less GC pauses".

http://en.wikipedia.org/wiki/Fewer_vs._less

Eric Cartman replied on Wed, 2011/07/20 - 9:02pm

I like reading your Java performance articles. Please keep it up.

Mike P(Okidoky) replied on Thu, 2011/07/21 - 12:30am

-Xincgc tends to give memory chunks back to the OS when it doesn't need it anymore, unlike the default GC which takes as much as it needs and never hands anything back to the OS. Does anyone know of any other GC options that also hand back memory that's no longer needed once the memory requirements of a running app goes down?

Stefan Krause replied on Thu, 2011/07/21 - 1:28am

I can't check right now, but I think there are collectors that react to the MaxHeapFreeRatio and MinHeapFreeRatio options. And if I'm not completely mistaken, ParNew and Serial Old return memory to the OS if configured properly (e.g. -XX:+UseParNewGC -XX:MaxHeapFreeRatio=20 -XX:MinHeapFreeRatio=10)

 

Javin Paul replied on Thu, 2011/07/21 - 10:36am

This   one is new "-XX:+UseCompressedStrings" I was not aware of that though in most project I found String as major source of garbage and reducing string garbage and turing GC parameter to have fewer mjaor collection improves performance signifcantly.

Javin
How Garbage collection works in Java

Peter Lawrey replied on Sat, 2011/07/23 - 1:10pm in response to: Bruce Fancher

Thank you, I will use less, less often. ;)

Nick Maiorano replied on Thu, 2012/01/05 - 4:11pm

No disrespect to the author but this is a decent article - not a top article of 2011. If we're going to use page views as a metric for quality, then I'll use "Kim Kardashian" as my new Javalobby handle.

On a more serious note, blindly increasing the eden size of your GC will not necessarily yield better results. Finding the right size is about finding the sweet spot: having a nursery that is too small or too big will decrease performance. And it all depends on your configured GC algorithm, heap size, application behavior and sometimes, the phase of the moon.

Mitch Pronschinske replied on Thu, 2012/01/05 - 4:13pm in response to: Nick Maiorano

Thanks for your feedback, Nick.  Page views were just one of the metrics we used to guide our pics, but comments generated were another.

I'd be very interested to hear which articles you would consider the top ones of 2011.

Nick Maiorano replied on Thu, 2012/01/05 - 9:11pm in response to: Mitch Pronschinske

I can tell you about the kind articles I do like. With some authors, you know you'll get quality so those are worthy of attention (here I'm thinking about thought leaders and experts within their domain). I also respect authors who post frequently because I know that it takes a lot of effort to write an article.

Conversely, I can tell you about the types of articles I don't like. For example, those with bad grammar, spelling or punctuation, written in a texting style (smiley faces, LOLs, "cant" instead of "can't"). I also don't have patience for articles that dive deep into details within the first sentence without giving readers appropriate context.

There was nothing wrong with this particular article but I guess my expectations were high when Javalobby labelled it as one of the top articles of 2011 out of thousands and thousands of articles.

Peter Lawrey replied on Mon, 2012/01/30 - 11:42am in response to: Nick Maiorano

I agree that top doesn't imply quality, but page views or votes is an objective measure used in democracies, for better or worse.

 I agree there is an optimal eden size, however I find increasing it is one of the first things to be tried if you have the memory.  This assumes you have the memory to experiement with this. (And you are not using a resource limited system e.g. a mobile deive or client PC)

James Walker replied on Wed, 2012/06/20 - 7:27am

This is really helpful. Designed for both production and development time use, it further enhances the capability of monitoring and performance analysis for the Java SE platform parkzone

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.