5 tips to reduce Java garbage collection overhead

Source: Internet
Author: User

This article is reprinted in an article on the internet, after watching the feeling good, benefited a lot, so here to share to everyone.

Original:


What are the tips for keeping GC low cost?


The JAVA9,G1 ("garbage first") garbage collector, which is about to be released with repeated delays, will be the default garbage collector for the HotSpot virtual machine. From the serial garbage collector

To the CMS collector, the JVM has witnessed many GC implementations, and G1 will become its next-generation garbage collector.


With the development of the garbage collector, each generation of GC compared with the previous generation, has brought great progress and improvement. Compared to the serial GC, the parallel GC allows the garbage collector to

Multi-threaded way of working, taking full advantage of the computing power of multicore computers. The CMS ("Concurrent mark-sweep") collector, compared to the parallel GC, divides the recycling process into multiple

Stage, the collection work can be completed concurrently while the application thread is running, greatly improving the frequent execution of the "Stop-the-world" situation. G1 for JVMs with a large heap of memory

Show better performance and have a better predictable and unified pause process.


Tip #1: Predicting the capacity of a collection


All standard Java collections, including custom and extended implementations (such as Trove and Google's guava), use arrays (native data types or object-based types) at the bottom. Because

Once an array is assigned, its size is immutable, so when adding elements to the collection, most of the time it will result in the need to reapply for a new large-capacity array to replace the old array (referred to as the bottom of the collection

Implements the array to use). Even if the size of the set initialization is not provided, most implementations of the collection try to optimize the handling of the reassigned array and minimize its overhead. However, in the construction set

The best result is the size you provide when you close it. Let's analyze the following code as a simple example:


public static list Reverse (List < extends T > list) {     list result = new ArrayList ();     for (int i = List.size ()-1; i > = 0; i--) {        Result.add (List.get (i));    }     return result;}


This method is allocates a new array, then fills it up with the items from the another list, only in reverse order. This method assigns a new array and then uses the

Another list element fills the array, but the order of the elements changes.


This approach can be costly in performance, and its optimized point is to add elements to the new list in this line of code. As you add elements every time, the list needs to ensure that its underlying array

Have enough space to accommodate the new element. If there is an idle position, then simply store the new element in the next free slot. If not, a new underlying array is assigned,

Copy the old array contents into the new array, and then add the new elements. This causes the array to be allocated multiple times, and those remaining old arrays are eventually reclaimed by the GC.


We can avoid these extra allocations by letting the underlying array know how many elements it will store when constructing the collection.

public static list Reverse (List < extends T > list) {     list result = new ArrayList (List.size ());     for (int i = List.size ()-1; i > = 0; i--) {        Result.add (List.get (i));    }     return result; }

The above code specifies enough space to store list.size () elements through the ArrayList constructor, which completes the execution of the assignment at initialization, which means that the list is in the process of iterating

There is no need to allocate memory again. The Guava collection class is further, allowing the initialization of the collection to explicitly specify the number of expected elements or to specify a forecast value.

List result = Lists.newarraylistwithcapacity (List.size ()); List result = Lists.newarraylistwithexpectedsize (List.size ());


In the above code, the former is used to know exactly how many elements the collection will store, and the latter's allocation takes into account the error estimate.


Tip #2: Working directly with Data flow


The following code is very common when working with data streams, such as reading data from a file or downloading data from a network:

byte[] FileData = Readfiletobytearray (New File ("MyFile.txt"));
The
resulting byte array may be parsed by an XML document, a JSON object, or a protocol buffer message, as well as some common optional options.


When dealing with large files or the size of a file cannot be predicted, the above approach is unwise, because when the JVM cannot allocate a buffer to process the real file, it causes

Outofmemeoryerrors. Even if the size of the data is manageable, when it comes to garbage collection, using the above pattern can still cause significant overhead because it allocates a very large area in the heap

To store file data. A better way to do this is to use the appropriate inputstream (for example, in this case, using FileInputStream) to pass directly to the parser, no longer once the entire file

Read into a byte array. All major open source libraries provide the appropriate API to directly accept an input stream for processing, such as:

FileInputStream fis = new FileInputStream (fileName); Myprotobufmessage msg = Myprotobufmessage.parsefrom (FIS);


Tip #3: Using Immutable objects


There are too many benefits to immutability. I don't even have to repeat anything. However, there is one advantage that can have an impact on garbage collection and should be followed.


The properties of an immutable object cannot be modified after the object is created (in this case, the properties of the reference data type are used), such as:

public class Objectpair {      private final Object first;    Private final Object second;      Public Objectpair (object first, object second) {        this.first = first;        This.second = second;    }      Public Object GetFirst () {        return first;    }      Public Object Getsecond () {        return second;    }  }

instantiating the above class results in an immutable object-all its properties are final decorated and cannot be changed once the construction is complete.
immutability means that all objects referenced by an immutable container are created before the container is constructed. In the case of GC: This container is at least as young as the year it holds
The same as a light reference. This means that when garbage collection is performed in younger generations, the GC skips them because the immutable objects are in the old age, until they are determined that the immutable objects are not in the old age by any object

When they are referenced, they are only completed for recycling.

Fewer scan objects mean fewer scans of memory pages, less scanning of memory pages means shorter GC lifecycles, and shorter GC pauses and better overall throughput. ".


Tip #4: Watch out for string stitching


The string may be the most common non-native data structure in all JVM-based applications. However, due to its implicit overhead and ease of use, it is very easy to become the culprit for the memory-intensive crime.
The problem is obviously not in string literals, but in allocating memory initialization at run time. Let's take a quick look at examples of dynamic build strings:

public static string toString (t[] array) {      string result = "[";      for (int i = 0; i < Array.Length; i++) {        result + = (Array[i] = = array? "This": Array[i]);        if (I < array.length-1) {            result + = ",";        }    }      Result + = "]";      return result;}

This is a seemingly good way to receive a character array and then return a string. However, this is catastrophic for object memory allocation.


It's hard to see behind this grammatical sugar, but the reality behind the scenes is this:

public static string toString (t[] array) {      string result = "[";      for (int i = 0; i < Array.Length; i++) {          StringBuilder sb1 = new StringBuilder (result);        Sb1.append (Array[i] = = array? "This": Array[i]);        result = Sb1.tostring ();          if (I < array.length-1) {            StringBuilder sb2 = new StringBuilder (result);            Sb2.append (",");            result = Sb2.tostring ();        }    }      StringBuilder SB3 = new StringBuilder (result);    Sb3.append ("]");    result = Sb3.tostring ();      return result;}
Strings are immutable, which means that each time a splice occurs, they are not modified by themselves, but instead they are assigned a new string. In addition, the compiler uses the standard StringBuilder class to perform

These stitching operations. This can be problematic because each iteration implicitly allocates a temporary string and implicitly assigns a temporary StringBuilder object to help build the final result as well.

The best way is to avoid the above situation, using StringBuilder and direct append to replace the local concatenation operator ("+"). Here is an example:

public static String toString (t[] array) {      StringBuilder sb = new StringBuilder ("[");      for (int i = 0; i < Array.Length; i++) {        sb.append (array[i] = = array? "This": Array[i]);        if (I < array.length-1) {            sb.append (",");        }    }      Sb.append ("]");    return sb.tostring ();}
Here, we only assign the only one StringBuilder at the beginning of the method. At this point, all the strings and elements in the list are appended to a single StringBuilder. End Use

The ToString () method turns it back into a string at once.


Tip #5: Using a specific collection of native types


The Java standard Collection library is simple and supports generics, allowing semi-static binding of types when using collections. For example, if you want to create a Set or storage map<pair that only holds strings, list> such

Map, this is a great way to handle it. The real problem arises when we want to use a list to store the int type, or a map to store a double type as value. Because generics do not support native data classes

Type, so another option is to use the wrapper type for the replacement, where we use List.

This processing is very wasteful because an integer is a complete object, the head of an object takes up 12 bytes and its internal int attribute is maintained, each integer object occupies a total of

With 16 bytes. It consumes four times times more space than a list that stores the same number of int types! The more serious problem is that, in fact, because the Integer is a real object instance, it

The garbage collection phase needs to be considered for recycling by the garbage collector.

To deal with this problem, we use a very good Trove collection library in Takipi. Trove abandons the specific set of generics to support a specific collection of native types that use memory more efficiently. For example, I

Map<integer, double&gt with very expendable performance, there is another special option in Trove, in the form of Tintdoublemap.


Tintdoublemap map = new Tintdoublehashmap () Map.put (5, 7.0); Map.put (-1, 9.999);

The underlying implementation of Trove uses an array of primitive types, so no element boxing (Int->integer) or unboxing (integer->int) occurs when the collection is manipulated, because the underlying uses the original

stored in the native data type.


At last


As the garbage collector continues to improve, and the runtime's optimizations and JIT compilers become more and more intelligent. As a developer, we will find that we are increasingly thinking less about how to write GC-friendly code. However

, at this stage, we still have a lot to do to help the JVM improve performance, no matter how G1 is improved.


original link: takipi translation: importnew.com - Pan
Link: http://www.importnew.com/20656.html







5 tips to reduce Java garbage collection overhead

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.