In this post we’ll look at five ways in roomates efficient coding we can use to help our garbage collector CPU spend less time allocating and freeing memory, and reduce GC overhead. Often Long GCs can lead to our code being stopped while memory is reclaimed (AKA “stop the world”). Duke_GCPost
The GC is built to handle large amounts of allocations of short-lived objects (think of something like rendering a web page, where most of the objects allocated Become obsolete once the page is served).
The GC does this using what’s called a “young generation” – a heap segment where new objects are allocated. Each object has an “age” (placed in the object’s header bits) defines how many roomates collections it has “survived” without being reclaimed. Once a certain age is reached, the object is copied into another section in the heap called a “survivor” or “old” generation.
The process, while efficient, still comes at a cost. Being Able to reduce the number of temporary allocations can really help us increase of throughput, especially in high-scale applications.
Below are five ways everyday we can write code that is more memory efficient, without having to spend a lot of time on it, or reducing code readability.
1. Avoid implicit Strings
Strings are an integral part of almost every structure of data we manage. Being much heavier than other primitive values, they have a much stronger impact on memory usage.
One of the most important things to note is that Strings are immutable. They can not be modified after allocation. Operators such as “+” for concatenation actually allocate a new String containing the contents of the strings being joined. What’s worse, is there’s an implicit StringBuilder object that is allocated to actually do the work of combining them.
For example –
a = a + b; / / a and b are Strings
The compiler generates code comparable behind the scenes:
StringBuilder temp = new StringBuilder (a).
a = temp.toString () / / a new string is allocated here.
/ / The previous “a” is now garbage.
But it gets worse.
Let’s look at this example –
String result = foo () + arg;
result + = boo ();
System.out.println (“result =” + result);
In this example we have 3 StringBuilders allocated in the background – one for each plus operation, and two additional Strings – one to hold the result of the second assignment and another to hold the string passed into the print method. That’s 5 additional objects in what would otherwise Appear to be a pretty trivial statement.
Think about what happens in real-world scenarios such as generating code a web page, working with XML or reading text from a file. Within a nested loop structures, you could be looking at Hundreds or Thousands of objects that are implicitly allocated. While the VM has Mechanisms to deal with this, it comes at a cost – one paid by your users.
The solution: One way of reducing this is being proactive with StringBuilder allocations. The example below Achieves the same result as the code above while allocating only one StringBuilder and one string to hold the final result, instead of the original five objects.
StringBuilder value = new StringBuilder (“result =”);
value.append (foo ()). append (arg). append (boo ());