Last updated: 19 May 2013
Next expected update: 31 May 2013
Russian translation is available here.
Русский перевод этой страницы находится здесь.
This is a summary of Java performance tuning tips described on java-performance.info website. This page will be updated after publishing a new article on Java performance tuning website.
Unlike most of Java performance books, this guide targets tuning your Java code instead of your JVM settings.
Java collections overview: all JDK 1.7 standard collections are described and categorized in this overview.
Here is a very brief summary of all JDK collections:
|Queues / deques||
java.util.ArrayList performance guide:
Try to follow these rules while using
subList(int, int).clear()idiom to quickly clean a part of the list
If you need to write fast
LinkedList code, try to stick to these rules:
ArrayDequefor queue-based algorithms
LinkedListmethods which accept or return index of an element in the list - they have nothing in common with performance
Regexp-related methods of String:
String.matches, split, replaceAll, replaceFirstmethods with
Patternmethods - it will save you from unnecessary pattern compilation.
String.splitmethod. Always use
String.splitto split such strings in Java 7.
Patternmethods with handcrafted methods.
java.util.Date, java.util.Calendar and java.text.SimpleDateFormat performance:
java.text.SimpleDateFormat: date storage,
parsing and converting back to string:
java.util.Dateunless you have to use it. Use an ordinary
java.util.Calendaris useful for all sorts of date calculations and i18n, but avoid either storing a lot of such objects or extensively creating them - they consume a lot of memory and expensive to create.
java.text.SimpleDateFormatis useful for general case datetime parsing, but it is better to avoid it if you have to parse a lot of dates in the same format (especially dates without time). Implement a parser manually instead.
Joda Time library performance:
This is a comparison of Joda Time library classes performance with standard JDK classes performance (
java.text.SimpleDateFormat). I advice you to read this article in conjunction with a
java.util.Date, java.util.Calendar and java.text.SimpleDateFormat performance
longtimestamp, so it is cheap to create those objects from a
GregorianCalendar. On the contrary, time components operations are about the same 3.5 times faster than a
SimpleDateFormat. The advantage of Joda parsing is that creating a parser -
DateTimeFormatterobject is extremely cheap, unlike an expensive
SimpleDateFormat, so you don't have to cache parsers anymore.
Performance of various methods of binary serialization in Java:
java.io.ByteArrayOutputStream: comparison of binary
serialization performance using various classes:
ByteBufferbulk methods performance is close to those of
ByteBuffermethods are always a little slower). If you need to store/load any other primitive array except
ByteBuffer.to[YourType]Buffer.put(array)method call followed by your byte buffer position update. Do not call
ByteBuffer.put[YourType]method in a loop!
ByteBufferaccesses were seriously optimized compared to Java 6.
Unsafeperformance and it is portable, unlike
java.nio.ByteBuffer: why you should not use
ByteArrayOutputStream in the performance critical code.
ByteArrayOutputStream. If you still want to use
ByteArrayOutputStream- get rid of its synchronization.
OutputStream, always write your message to the
ByteArrayOutputStreamfirst and use its
writeTo(OutputStream)method after that. In some rare cases when you are building a
Stringfrom its byte representation, do not forget about
ByteArrayOutputStream.toByteArraymethod - it creates a copy of internal byte array. Garbage collecting these copies may take a noticeable time if your application is using a few gigabytes of memory (see Inefficient byte to String constructor article for another example).
java.io.BufferedInputStream and java.util.zip.GZIPInputStream:
some minor performance pitfalls in these two streams.
GZIPInputStreamhave internal buffers. Default size for the former one is 8192 bytes and for the latter one is 512 bytes. Generally it worth increasing any of these sizes to at least 65536.
BufferedInputStreamas an input for a
GZIPInputStream, instead explicitly set
GZIPInputStreambuffer size in the constructor. Though, keeping a
BufferedInputStreamis still safe.
new BufferedInputStream( new FileInputStream( file ) )object and you call its
availablemethod rather often (for example, once or twice per each input message), consider overriding
BufferedInputStream.availablemethod. It will greatly speed up file reading.
java.util.Set<Integer>: representing set of integers in the most compact form,
using bit sets to store set of
java.lang.Byte, Short, Integer, Long, Character (boxing and unboxing):
valueOf(String)methods. If you need a primitive value - call
parse[Type]. If you want an instance of a wrapper class, still call
parse[Type]method and rely on the JVM-implemented boxing. It will support caching of most frequently used values. Never call wrapper classes constructors - they always return a new
Object, thus bypassing the caching support. Here is the summary of caching support for primitive replacement classes:
|Byte, Short, Long||Character||Integer||Float, Double|
|From -128 to 127||From 0 to 127||From -128 to java.lang.Integer.IntegerCache.high or 127, whichever is bigger||No caching|
Using double/long vs BigDecimal for monetary calculations:
double(calculate in the smallest currency units).
Math.round/rint/ceil/floor(per your system requirements).
BigDecimalmultiplication and division in order to avoid
ArithmeticExceptionfor infinitely long decimal results. Don't use
MathContext.UNLIMITEDfor that reason - it is equivalent to no context at all.
BigDecimal, instead convert
discussion why an
IdentityHashMap is so special and what alternatives does it have.
System.identityHashCodeto get object identity hash code. Avoid using
IdentityHashMapif you either have primary key field in the objects (use them as a key for ordinary
HashMap) or use Trove maps custom hashing strategy if you need to add your own
hashCodemethods, but can't update the objects you are working on.
IdentityHashMap, be aware that it would still calculate object hash code in
containsKey. Add explicit emptiness check in such code, this would save you from JNI
java.util.Set and most of their implementations:
contains+add/removecall pairs should be replaced with single
add/removecalls even if some extra logic was guarded by
contains+getpair shall always be replaced with
contains+removepair should be replaced with a single
removecall and check of its result.
java.util.zip.CRC32 and java.util.zip.Adler32 performance:
Adler32first. If its quality is sufficient for you, use it instead of
CRC32. In any case, use
Checksuminterface in order to access
hashCode method performance tuning:
hashCodemethod. This is far more important than to optimize that method speed. Never write a
hashCodemethod which returns a constant.
String.hashCoderesults distribution is nearly perfect, so you can sometimes substitute
Strings with their hash codes. If you are working with sets of strings, try to end up with
BitSets, as described in this article. Performance of your code will greatly improve.
Changes to String internal representation made in Java 1.7.0_06:
String.substringalways creates a new underlying
char valuefor every
Stringit creates. This means that this method now has a linear complexity compared to previous constant complexity. The advantage of this change is a slightly smaller memory footprint of a
String(4 bytes less than before) and a guarantee to avoid memory leaks caused by
Stringclass got a second hashing method called
hash32. This method is currently not public and could be accessed without reflection only via
sun.misc.Hashing.stringHash32(String)call. This method is used by 7 JDK hash-based collections if their size will exceed
jdk.map.althashing.thresholdsystem property. This is an experimental function and currently I don't recommend using it in your code.
Throwing an exception in Java is very slow:
why it is too expensive to throw exceptions in Java:
parse*/valueOfmethods if you call them for each piece of your data and you expect a lot of non-numerical data. Parse such values manually for top performance.
Java logging performance pitfalls:
how to lose as little as possible performance while writing log messages:
Logger.isLoggableand do all data preparation inside or write an object which does all calculations in its
Object.toStringmethod in order to obtain a log message argument - just pass an original object. Logging framework will call
toStringmethod on your object.
Trove library: using primitive collections for performance: an overview of Trove library, which is a primitive type collection library.
hashCode, for example to implement identity set or map.
adjustOrPutValue. They allow to reduce code required for many common tasks.
Various types of memory allocation in Java: how to allocate a large memory buffer in Java and how to write any Java types into such buffer.
2^31 - 1. On the other hand, you are not limited by
2Gb - 1bytes as a size of your array - you may allocate a
long, which occupies 8 times more memory (
16Gb - 8bytes).
sun.misc.Unsafe.allocateMemory(long size)for allocating a buffer longer than 2Gb, but you will have to free such buffers yourself.
sun.misc.Unsafememory access methods for reading/writing any Java datatype from/to both Java arrays and
Unsafebuffers in the uniform manner.
Memory introspection using sun.misc.Unsafe and reflection:
how to find out Java object memory layout using
sun.misc.Unsafe and reflection.
sun.misc.Unsafemethods for obtaining Java object layout information:
Objectreference size depends on your environment. It may be equal to 4 or 8 bytes depending on your JVM settings and on the amount of memory you have given to your JVM. It is always 8 bytes for heaps over 32G, but for smaller heaps it is 4 bytes unless you will turn off
Use case: compacting price field disk representation:
java.math.BigDecimal: an example of compacting your data:
doublevalues in your disk data structures. Often same information may be represented in a smaller number of bytes (compare, for example, 0.01 converted with
3f 84 7a e1 47 ae 14 7b- binary representation of 0.01).
Use case: how to compact a long-to-long mapping: a use case where we try to identify some long-2-long mapping properties in order to represent it in the most compact form.
String packing part 1: converting characters to bytes:
we discuss Java objects memory layout and consumption. After that we try to pack a
String into a more compact representation, trying
to minimize using any
java.lang.Stringobjects were designed to be fast and flexible. That's why they can share internal
charwith other strings. They also cache the calculated hash code value, because strings are often used as
HashSetvalues. But these properties add a great penalty for short strings memory footprint. We can avoid this penalty by implementing our own string replacement objects.
-XX:+UseCompressedStringsoption. Unfortunately, it is not supported anymore in Java 7, maybe due to not so big memory savings as one may expect from it.
String packing part 2: converting Strings to any other objects:
we discuss how and when to convert a
String into various more compact Java objects for temporary string representation.
Stringfields in memory and you know that in some cases (at least at 10% of cases, for example) these strings may be actually converted to primitive type values, you may replace your
Objectfields and use provided
pack/unpackmethods to convert
Objects and back, thus saving memory.
bytein UTF-8 encoding. This is loseless conversion, so you could always convert your binary
byteback into an original string.
I/O bound algorithms: SSD vs HDD: This article will investigate an impact of modern SSDs on the I/O bound algorithms of HDD era.
Forbidden Java actions: object assignments,
type conversions etc on the low level in Java: This article will reveal you a few details about the low level Java memory layout: we will see how to implement
Object assignments using just primitive types. Then we will see what's hidden in the array header and will
convert an array of one type into an array of another type.
sun.misc.Unsafein order to treat such references as
intat the offset=8 in the array header. Length (
int) is stored at offset=12. Changing these values is possible, but care must be taken in order not to extend an updated array outside of initially allocated memory.
Forbidden Java actions: updating final and static final fields:
This article will discuss how you can update
static final fields in Java using reflection and
finalfield using Java reflection - make a
Method/Field.setAccessible( true )and then set a new field value.
final staticfield using reflection - you will need to make 2 steps: make the field itself accessible and then make accessible
Fieldyou want to update and remove
Fieldmodifiers. Such updates to static final fields of primitive/
Stringinitialized with complile-time expressions will not be visible to clients, because static fields initialized with constant expressions (JLS 15.28) are inlined.
static finalfields using
Unsafe.putN( base, offset, newValue )methods for updates.
baseis the owner of a field for instance fields and the
Classobject for static fields.
offsetcould be obtained with
Unsafe.objectFieldOffset( Field )for instance fields and
Unsafe.staticFieldOffset( Field )for static fields.
Forbidden Java actions: not declaring a checked exception; avoiding a constructor while creating an object:
In this article we will see how to throw a checked exception in Java without declaring it in the method
throws clause and how to create an object without calling any of its constructors.
Class.newInstance(and throw an exception in the constructor),
sun.misc.Unsafe.throwExceptionor use generic type erasure in order to avoid a checked exception declaration in the
throwsclause. We do not recommend you to use any of these practices :)
sun.misc.Unsafeallows you to create an uninitialized instance of an object bypassing its constructors using
Static constructor code is not JIT-optimized in a lot of cases: Static constructor code is generally executed in the interpreted mode, even if you have a heavy calculations in it. But there is a way to force it run in the compiled mode:
Inefficient byte to String constructor: be careful when using
public String(byte bytes, int offset, int length, Charset charset) constructor in Java 6:
In this set of articles we try to apply principles discussed in the other articles to the "real world" problems.
Use case: FIX messages processing. Part 1: Writing a simple FIX parser and
Use case: FIX messages processing. Part 2: Composing a message out of fields: possible gateway implementation:
a tag-based FIX message parsing and composing
is described in two these articles. In essence, we parse a
0x0001 separated string into a list of
name=value tags, which are converted to actual datatypes after that. In the second part we will discuss
a best way to compose these messages back to String format as a part of a gateway implementation.
String.splitshould usually be avoided. The only exception is a single character pattern in Java 7. You can still write faster code even in this case, but you should add some parsing logic into a splitting loop.
String.indexOf(char)with separator character is a far better alternative.
Use case: Optimizing memory footprint of a read only csv file (Trove, Unsafe, ByteBuffer, data compression):
we will see how to optimize memory consumption of a Java program which has to store a large set of readonly data in memory
We will also try replacing index fields with their hash codes, still supporting the case of hash code collisions.
ByteBuffer) or hash code is sufficient as a key.