5 Coding Hacks to Reduce GC Overhead

Some background

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) which defines how many 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 throughput, especially in high-scale environments, or Android apps where resources are more limited.

Below are five ways we can write everyday code that’s 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 data structure 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 cannot 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’s allocated to actually do the work of combining them.

For example –

1
a = a + b; // a and b are Strings

The compiler generates comparable code behind the scenes:

1
2
3
4
StringBuilder temp = new StringBuilder(a).
temp.append(b);
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 –

1
2
3
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 code scenarios such as generating a web page, working with XML or reading text from a file. Nested within 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.

1
2
3
StringBuilder value = new StringBuilder(“result = “);
value.append(foo()).append(arg).append(boo());
System.out.println(value);

By being mindful of the way Strings and StringBuilders are implicitly allocated you can materially reduce the amount of short-term allocations in high-scale code locations.

2. Plan List capacities

Dynamic collections such as ArrayLists are among the most basic structures to hold dynamic length data. ArrayLists and other collections such as HashMaps and TreeMaps are implemented using underlying Object[] arrays. Like Strings (themselves wrappers over char[] arrays), array size is also immutable. The obvious question then becomes – how can we add/put items in collections if their underlying array’s size is immutable? The answer is obvious as well – byallocating more arrays.

Let’s look at this example –

1
2
3
4
5
6
7
List<Item> items = new ArrayList<Item>();
for (int i = 0; i < len; i++)
{
Item item = readNextItem();
items.add(item);
}

The value of len determines the ultimate length of items once the loop finishes. This value, however, is unknown to the constructor of the ArrayList which allocates a new Object array with a default size. Whenever the capacity of the internal array is exceeded, it’s replaced with a new array of sufficient length, making the previous array garbage.

If you’re executing the loop thousands of times you may be forcing a new array to be allocated and a previous one to be collected multiple times. For code running in a high-scale environment, these allocations and deallocations are all deducted from your machine’s CPU cycles.

The solution: Whenever possible, allocate lists and maps with an initial capacity, like so:

1
List<MyObject> items = new ArrayList<MyObject>(len);

This ensures that no unnecessary allocations and deallocations of internal arrays occur at runtime as the list now has sufficient capacity to begin with. If you don’t know the exact size, it’s better to go with an estimate (e.g. 1024, 4096) of what an average size would be, and add some buffer to prevent accidental overflows.

3. Use efficient primitive collections

Current versions of the Java compiler support arrays or maps with a primitive key or value type through the use of “boxing” – wrapping the primitive value in a standard object which can be allocated and recycled by the GC.

This can have some negative implications. Java implements most collections using internal arrays. For each key/value entry added to a HashMap an internal objectis allocated to hold both values. This is a necessary evil when dealing with maps, which means an extra allocation and possible deallocation made every time you put an item into a map. There’s also the possible penalty of outgrowing capacity and having to reallocate a new internal array. When dealing with large maps containing thousands or more entries, these internal allocations can have increasing costs for your GC.

A very common case is to hold a map between a primitive value (such as an Id) and an object. Since Java’s HashMap is built to hold object types (vs. primitives), this means that every insertion into the map can potentially allocate yet another object to hold the primitive value (“boxing” it).

The standard Integer.valueOf method caches the values between -128 and 127, but for each number outside that range, a new object will be allocated in addition to the internal key / value entry object. This can potentially more than triple GC overhead for the map. For those coming from a C++ background this can really be troubling news, where STL templates solve this problem very efficiently.

Luckily, this problem is being worked on for next versions of Java. Until then, it’s been dealt with quite efficiently by some great libraries which provide primitive trees, maps and lists for each of Java’s primitive types. I strongly recommend Trove, which I’ve worked with for quite a while and found that can really reduce GC overhead in high-scale code.

4. Use Streams instead of in-memory buffers

Most of the data we manipulate in server applications comes to us in the form of files or data streamed over the network from another web service or a DB. In most cases, the incoming data is in serialized form, and needs to be deserialized into Java objects before we can begin operating on it. This stage is very prone to large implicit allocations.

The easiest thing to do usually is read the data into memory using a  ByteArrayInputStream, ByteBuffer and then pass that on to the deserialization code.

This can be a bad move, as you’d need to allocate and later deallocate room for that data in its entirety while constructing new objects out of it . And since the size of the data can be of unknown size, you guessed it – you’ll have to allocate and deallocate internal byte[] arrays to hold the data as it grows beyond the initial buffer’s capacity.

The solution is pretty straightforward. Most persistence libraries such as Java’s native serialization, Google’s Protocol Buffers, etc. are built to deserialize data directly from the incoming file or network stream, without ever having to keep it in memory, and without having to allocate new internal byte arrays to hold the data as it grows. If available, go for that approach vs. loading the data into memory. Your GC will thank you.

5. Aggregate Lists

Immutability is a beautiful thing, but in some high-scale situations it can have some serious drawbacks. One scenario is when passing List objects between methods.

When returning a collection from a function, it’s usually advisable to create the collection object (e.g. ArrayList) within the method, fill it and return it in the form of an immutable Collection interface.

There are some cases where this doesn’t work well. The most noticeable one is when collections are aggregated from multiple method calls into a final collection. While immutability provides more clarity, in high-scale situations it can also mean massive allocation of interim collections.

The solution in this case would be not to return new collections, but instead aggregate values into a single collection that’s passed into those methods as a parameter.

Example 1 (inefficient) –

1
2
3
4
5
6
7
8
List<Item> items = new ArrayList<Item>();
for (FileData fileData : fileDatas)
{
// Each invocation creates a new interim list with possible
// internal interim arrays
items.addAll(readFileItem(fileData));
}

Example 2 –

1
2
3
4
5
6
7
List<Item> items =
new ArrayList<Item>(fileDatas.size() * avgFileDataSize * 1.5);
for (FileData fileData : fileDatas)
{
readFileItem(fileData, items); // fill items inside
}

Example 2, while disobeying the rules of immutability (which should normally be adhered to) can save N list allocations (along with any interim array allocations). In high-scale situations this can be a boon to your GC.

Additional reading

String interning – http://plumbr.eu/blog/reducing-memory-usage-with-string-intern

Efficient wrappers – http://vanillajava.blogspot.co.il/2013/04/low-gc-coding-efficient-listeners.html

Using Trove – http://java-performance.info/primitive-types-collections-trove-library/

FROM HERE

Advertisements

java vs c++

At the beginning of a new project, you may be faced with the question, “Should I use C++ (or some other language) for my next project, or should I use Java?” As an implementation language, Java has some advantages and some disadvantages over other languages. One of the most compelling reasons for using Java as a language is that it can enhance developer productivity. The main disadvantage is potentially slower execution speed.

Java is, first and foremost, an object-oriented language. One promise of object-orientation is that it promotes the re-use of code, resulting in better productivity for developers. This may make Java more attractive than a procedural language such as C, but doesn’t add much value to Java over C++. Yet compared to C++, Java has some significant differences that can improve a developer’s productivity. This productivity boost comes mostly from Java’s restrictions on direct memory manipulation.

In Java, there is no way to directly access memory by arbitrarily casting pointers to a different type or by using pointer arithmetic, as there is in C++. Java requires that you strictly obey rules of type when working with objects. If you have a reference (similar to a pointer in C++) to an object of type Mountain, you can only manipulate it as a Mountain. You can’t cast the reference to type Lava and manipulate the memory as if it were a Lava. Neither can you simply add an arbitrary offset to the reference, as pointer arithmetic allows you to do in C++. You can, in Java, cast a reference to a different type, but only if the object really is of the new type. For example, if the Mountain reference actually referred to an instance of class Volcano (a specialized type of Mountain), you could cast the Mountain reference to a Volcano reference. Because Java enforces strict type rules at run- time, you are not able to directly manipulate memory in ways that can accidentally corrupt it. As a result, you can’t ever create certain kinds of bugs in Java programs that regularly harass C++ programmers and hamper their productivity.

Another way Java prevents you from inadvertently corrupting memory is through automatic garbage collection. Java has a new operator, just like C++, that you use to allocate memory on the heap for a new object. But unlike C++, Java has no corresponding delete operator, which C++ programmers use to free the memory for an object that is no longer needed by the program. In Java, you merely stop referencing an object, and at some later time, the garbage collector will reclaim the memory occupied by the object.

The garbage collector prevents Java programmers from needing to explicitly indicate which objects should be freed. As a C++ project grows in size and complexity, it often becomes increasingly difficult for programmers to determine when an object should be freed, or even whether an object has already been freed. This results in memory leaks, in which unused objects are never freed, and memory corruption, in which the same object is accidentally freed multiple times. Both kinds of memory troubles cause C++ programs to crash, but in ways that make it difficult to track down the exact source of the problem. You can be more productive in Java primarily because you don’t have to chase down memory corruption bugs. But also, you can be more productive because when you no longer have to worry about explicitly freeing memory, program design becomes easier.

A third way Java protects the integrity of memory at run-time is array bounds checking. In C++, arrays are really shorthand for pointer arithmetic, which brings with it the potential for memory corruption. C++ allows you to declare an array of ten items, then write to the eleventh item, even though that tramples on memory. In Java, arrays are full-fledged objects, and array bounds are checked each time an array is used. If you create an array of ten items in Java and try to write to the eleventh, Java will throw an exception. Java won’t let you corrupt memory by writing beyond the end of an array.

One final example of how Java ensures program robustness is by checking object references, each time they are used, to make sure they are not null. In C++, using a null pointer usually results in a program crash. In Java, using a null reference results in an exception being thrown.

FROM HERE

Set tomcat memory heap size

when you are using tomcat as you application server for not small application you can easy get (out of memory exception). this is because the default heap size tomcat use is small and suitable only for small web applications.

to set the start and maximum heap size run the following command before starting your tomcat:

export CATALINA_OPTS=”-Xms1024m -Xmx1024m”

or

export JAVA_OPTS=”-Xms1024m -Xmx1024m”

or

go to the tomcat_HOME/bin/catalina.sh. find the JAVA_OPTS parameter and modify to JAVA_OPTS=”-Xms1024m -Xmx1024m”

this will create environment variable called CATALINA_OPTS  or JAVA_OPTS contains the required options to make tomcat start heap size 1024M and maximum heap size 1024M.

vps centos check cpu and memery usage

For memery use:

free -m

You will see an output like this:

total       used       free     shared    buffers     cached

Mem:           512        462         49          0         46        127

-/+ buffers/cache:        287        224

Swap:         2047          0       2047

The important figure to look at is the “used” number in the “buffers/cache” row. This will tell you how much memory your processes are currently using. Memory allocation errors will occur if this number is higher than the total amount of memory and swap space. To see how much RAM is free, check the “free” column in the “buffers/cache” row.

for running process check use:

ps aux

The output will look like this:
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.1  10368   632 ?        Ss   Jan07   0:00 init [3]
root         2  0.0  0.0      0     0 ?        S<   Jan07   0:00 [migration/0]
root         3  0.0  0.0      0     0 ?        SN   Jan07   0:00 [ksoftirqd/0]
One of the benefits of a VPS is that, in the case of a memory shortage, you can upgrade RAM on-the-fly with little (Xen) to no (OpenVZ) downtime. Open a support ticket, or find us on live chat, if you need an upgrade!
For active listening port:
netstat -ntplau