When the log shows a lot of GC hits, what code change do we need?

When the log shows a lot of garbage hits, what code change do we need?
Do we need to free some objects?
Are we going to speed up the code by re-declaring the object?

EDIT

I am running this code against a lot of names:

 public static String removeAccents(String s) {
        if (s == null)
            return null;
        StringBuilder sb = new StringBuilder();
        int n = s.length();
        for (int i = 0; i < n; i++) {
            char c = s.charAt(i);
            int pos = UNICODE.indexOf(c);
            if (pos > -1) {
                sb.append(PLAIN_ASCII.charAt(pos));
            } else {
                sb.append(c);
            }
        }
        return sb.toString();
    }

      

EDIT2

log GC

05-17 14:05:07.629: DEBUG/dalvikvm(8823): GC freed 13344 objects / 523736 bytes in 73ms
05-17 14:05:08.269: DEBUG/dalvikvm(8823): GC freed 13341 objects / 524608 bytes in 72ms
05-17 14:05:08.889: DEBUG/dalvikvm(8823): GC freed 13302 objects / 525112 bytes in 72ms
05-17 14:05:09.519: DEBUG/dalvikvm(8823): GC freed 13151 objects / 524360 bytes in 72ms
05-17 14:05:10.089: DEBUG/dalvikvm(8823): GC freed 13377 objects / 524384 bytes in 71ms
05-17 14:05:10.779: DEBUG/dalvikvm(8823): GC freed 13137 objects / 523872 bytes in 72ms
05-17 14:05:11.389: DEBUG/dalvikvm(8823): GC freed 13289 objects / 524656 bytes in 72ms
05-17 14:05:12.049: DEBUG/dalvikvm(8823): GC freed 13113 objects / 524336 bytes in 71ms
05-17 14:05:12.299: DEBUG/dalvikvm(4864): GC freed 206 objects / 10216 bytes in 358ms
05-17 14:05:12.769: DEBUG/dalvikvm(8823): GC freed 13289 objects / 524272 bytes in 75ms
05-17 14:05:13.449: DEBUG/dalvikvm(8823): GC freed 13165 objects / 524192 bytes in 68ms
05-17 14:05:14.099: DEBUG/dalvikvm(8823): GC freed 13221 objects / 524016 bytes in 73ms
05-17 14:05:14.719: DEBUG/dalvikvm(8823): GC freed 13179 objects / 524768 bytes in 73ms
05-17 14:05:15.349: DEBUG/dalvikvm(8823): GC freed 13306 objects / 524328 bytes in 73ms
05-17 14:05:15.999: DEBUG/dalvikvm(8823): GC freed 13280 objects / 523536 bytes in 73ms
05-17 14:05:16.589: DEBUG/dalvikvm(8823): GC freed 13314 objects / 524928 bytes in 68ms
05-17 14:05:17.249: DEBUG/dalvikvm(8823): GC freed 13217 objects / 524792 bytes in 73ms
05-17 14:05:17.929: DEBUG/dalvikvm(8823): GC freed 13176 objects / 524104 bytes in 68ms
05-17 14:05:18.449: DEBUG/dalvikvm(9926): GC freed 10341 objects / 558184 bytes in 488ms
05-17 14:05:18.689: DEBUG/dalvikvm(8823): GC freed 13485 objects / 524664 bytes in 75ms
05-17 14:05:19.279: DEBUG/dalvikvm(8823): GC freed 13337 objects / 523816 bytes in 67ms
05-17 14:05:19.909: DEBUG/dalvikvm(8823): GC freed 13269 objects / 524784 bytes in 72ms
05-17 14:05:20.419: DEBUG/dalvikvm(8823): GC freed 13389 objects / 524416 bytes in 72ms
05-17 14:05:21.069: DEBUG/dalvikvm(8823): GC freed 12948 objects / 523712 bytes in 72ms
05-17 14:05:21.659: DEBUG/dalvikvm(8823): GC freed 13436 objects / 525040 bytes in 68ms

      

Do you think this is too much?

+2


a source to share


4 answers


Frequent garbage collection can be caused by a number of things. For instance:

  • Too many temporary objects may be created in your application.

  • Memory leaks caused by your application retaining references to objects that are no longer required.

  • The heap may be too small.

The first two problems will be discovered if you run a memory profiler in your application, and the solution will usually be taken for granted.

The third issue can be seen by examining the GC logs and noting that each GC run is only performed when recovering a relatively small amount of memory. Ideally, you want the GC to run 50% or more of the heap every time. The fix usually increases the maximum heap size using the JVM command line parameter -Xmx

.

Are we going to speed up the code by re-declaring the object?

Actually no. Disposal is painful, there is no guarantee that it will be successful. For example, you will have a hard time getting a lot of classes in the Java standard library and third party libraries to recycle internal data structures.

You should only resort to explicit utilities if all other attempts to fix the problem have failed. The simplest solution is to just give the application a big heap.

EDIT



One way to reduce memory usage for the code in the edited question is to change:

   StringBuilder sb = new StringBuilder();

      

to

   StringBuilder sb = new StringBuilder(s.length());

      

This can help reuse the StringBuilder, but if this code gives you excessive GC rates, the problem is more likely that there is a memory leak (somewhere in your application) or that your heap is just too small. (People don't realize this, but there is a significant memory overhead for every Java line ... something like 48 bytes if my mental arithmetic is correct.)

EDIT 2

The GC logs say that every time the GC is run you are returning 50,000 KB and they strongly recommend that memory usage does not increase. (The latter is good news, largely eliminates memory leaks.) I think you need to increase the heap size using the -Xmx

and options -Xms

. You want to recover a few megabytes in each GC cycle to reduce the average GC overhead per byte patched.

Another thing that struck me is that perhaps you can change your method removeAccents

so that it only creates a new String if the String result is different from the input String. In other words, if there are no accents, it should just return the input string.

+4


a source


If the GC runs frequently, this is a good warning sign that many temporary objects are being created. This significantly slows down application performance as the garbage collector tries to clean up unrecognized objects on the heap. To counter this, you can view the profile and find out the points of improvement. An example of creating a set of temporary objects will be the following piece of code:

String str = "";    
for(int i=0;i<1000000;i++){
   str = str + String.valueOf(i);
}

      



To avoid creating a lot of objects, you can replace the above code snippet with StringBuffer / StringBuilder.

+1


a source


Your code generates a lot of heap allocated short-lived objects. This is a GC dream: GC is optimized to handle this particular situation. Unsurprisingly, you see a lot of GC calls, but that's ok, expected, and doesn't slow down your code. In the log file, you can see that each GC run takes about 70ms and happens twice per second; that's 14% of your time at most. In other words, even if you remove all heap allocations thanks to the wonders of object recycling, you will get a speedup of no more than 16%.

If there is anything that makes your code slow, this line:

int pos = UNICODE.indexOf(c);

      

and it has nothing to do with GC. This string does a linear search on the string UNICODE

(I assume this is an instance String

) and it will probably be computationally expensive (I assume the specified string is somewhat large).

I suggest you try replacing this line:

int pos = (c <= 126) ? -1 : UNICODE.indexOf(c);

      

which is to avoid scanning the entire line for every ASCII character (I assume most of the input characters don't have any accent to remove).

For a more complete treatment of accent removal, use java.text.Normalizer

(with the NFKD form), then for each resulting code point, get your category (c Character.getType()

) and discard all code points that have a category COMBINING_SPACING_MARK

, ENCLOSING_MARK

and NON_SPACING_MARK

. This will handle all Unicode at its best, but will probably be more costly.

+1


a source


it could be int pos

create / destroy calling GC.

Try declaring it outside of the for loop and just reset it to -1 as the first line inside the for loop.

 public static String removeAccents(String s) { 
    if (s == null) 
        return null; 
    StringBuilder sb = new StringBuilder(); 
    int n = s.length(); 
    int pos = -1;
    for (int i = 0; i < n; i++) { 
        pos = -1; //set it here just in case.
        char c = s.charAt(i); 
        pos = UNICODE.indexOf(c); 
        if (pos > -1) { 
            sb.append(PLAIN_ASCII.charAt(pos)); 
        } else { 
            sb.append(c); 
        } 
    } 
    return sb.toString(); 
} 

      

The same happens for char c, create it outside of the for loop and reset it inside it every time you need it.

-2


a source







All Articles