Java Heap Sizing: How do I size my Java heap correctly?

Proper heap sizing is key to good Java application performance. Whether running a client or server application, if your system is running low on heap and spending a lot of time with garbage collection you'll want to investigate adjusting your heap size. You also don't want to set your heap size too large and impact other applications running on the system. This edition of JVM Performance Tuning Basics will cover general heap and generation tuning steps, and new features in JDK 5.0. h2. Java SE 5.0 Ergonomics Ergonomics for servers was first introduced in Java SE 5.0. It has greatly reduced application tuning time for server applications, particularly with heap sizing and advanced GC tuning. In many cases no tuning options when running on a server is the best tuning you can do. Server ergonomics is enabled when running on a server class machine on Solaris, Linux, and 64-bit Windows. It is disabled by default when running on 32-bit Windows. Ergonomics does the following: \* Throughput garbage collector and Adaptive Sizing (-XX:+UseParallelGC) \* Initial heap size of 1/64 of physical memory up to 1Gbyte \* Maximum heap size of 1/4 of physical memory up to 1Gbyte \* Server runtime compiler (-server) To enable server egonomics on 32-bit Windows, use the following flags: -server -Xmx1g -XX:+UseParallelGC (varying the heap size) h2. Identify how much Java heap your application needs. There are several ways to identify how much heap your application is using. Java SE has a suite of monitoring tools such as jstat and jconsole. There is Brian Doherty's jvmstat tools, in particular visualgc. Then there is the tried and true -verbosegc and -XX:+PrintGCDetails. For this example I'll use -verbosegc. For details on GC implementation and logging outputs, take a look here: Details on Garbage Collection Tuning with Java SE 5.0 Examples of verbosegc and -XX:+PrintGCDetails. h3. -verbosegc The first step in investigating GC performance problems is looking at -verbosegc output. The following example is a server application with a heap size fixed at 64mb. The server compiler is specified and default GC collectors are chosen. In this case J2SE 1.4.2 is running with the default serial GC collectors. java -server -Xms80m -Xmx80m my.serverApp

[GC 55974K->35946K(79232K), 0.0269796 secs]
[GC 57834K->36306K(79232K), 0.0278222 secs]
[GC 58194K->36669K(79232K), 0.0264892 secs]
[GC 58557K->37044K(79232K), 0.0223606 secs]
[GC 58932K->37400K(79232K), 0.0262330 secs]

[GC 59288K->37803K(79232K), 0.0271792 secs]
[GC 59691K->38097K(79232K), 0.0283054 secs]
[GC 59985K->38516K(79232K), 0.0276064 secs]
[GC 60404K->38847K(79232K), 0.0244366 secs]
[GC 60735K->43570K(79232K), 0.0732041 secs]
[GC 65458K->56730K(79232K), 0.1476127 secs]
[Full GC 78618K->61524K(79232K), 0.8851303 secs]
[Full GC 79231K->61898K(79232K), 0.9426240 secs]
[Full GC 79231K->62263K(79232K), 0.9828957 secs]
[Full GC 79231K->59527K(79232K), 1.0334212 secs]
[Full GC 79231K->59906K(79232K), 0.9298369 secs]
[Full GC 79231K->60014K(79232K), 0.8833146 secs]
[Full GC 79231K->60124K(79232K), 0.8293863 secs]
[Full GC 79231K->59615K(79232K), 0.8944206 secs]
[Full GC 79231K->59679K(79232K), 0.9169885 secs]
[Full GC 79231K->59626K(79232K), 0.9366790 secs]
[Full GC 79231K->59697K(79232K), 0.8613183 secs]
[Full GC 79231K->59594K(79232K), 0.9114757 secs]
[Full GC 79231K->59654K(79232K), 0.9987619 secs]
[Full GC 79231K->59654K(79232K), 1.0146781 secs]
[Full GC 79231K->59661K(79232K), 0.9687409 secs]

The first 11 lines of verbose gc output is young generation garbage collection. The first number is the size of the heap before the GC, the second number is the size afterwards. The third number is the overall heap size, the forth it the time spent during the GC operation. [GC 60404K->38847K(79232K), 0.0244366 secs] # 60404K # 38847K # 79232K # 0.0244366 secs Note that the second number continues to grow during the first 11 GCs. This is an indication that many objects are being promoted to the old (tunured generation). There are several reasons this may occur. First is the obvious, most object continue to be live and are properly tenured. Second is that the young generation is not large enough to allow transient objects to successfully die in the young generation. Also note that eventually young GCs cease and only Full GC operations occur there after. When running the serial collector, there must be enough space in the tenured generation to allow full promotion of the young generation plus one survivor space. This is known as the . If there isn't enough space and the guarantee is not upheld, then only Full GCs occur. Simply increasing the size of the heap slightly to 128mb is enough to uphold the young generation guarantee and avoids a majority of the Full GCs. java -server -Xms128m -Xmx128m my.serverApp

[GC 109920K->75933K(126720K), 0.0533675 secs]
[GC 110877K->76916K(126720K), 0.0437944 secs]
[GC 111860K->77818K(126720K), 0.0490449 secs]
[GC 112762K->78812K(126720K), 0.0482215 secs]
[GC 113756K->79810K(126720K), 0.0444408 secs]
[GC 114754K->80759K(126720K), 0.0502736 secs]
[GC 115703K->81657K(126720K), 0.0435275 secs]
[GC 116601K->82629K(126720K), 0.0521527 secs]
[GC 117573K->83564K(126720K), 0.0443587 secs]
[GC 118508K->84501K(126720K), 0.0438583 secs]
[GC 119445K->85492K(126720K), 0.0556998 secs]
[GC 120436K->86412K(126720K), 0.0437702 secs]
[GC 121356K->87402K(126720K), 0.0478918 secs]
[Full GC 122346K->59749K(126720K), 0.9128712 secs]
[GC 94693K->63029K(126720K), 0.0415602 secs]
[GC 97973K->64037K(126720K), 0.0442277 secs]
[GC 98981K->65123K(126720K), 0.0538927 secs]
[GC 100067K->66058K(126720K), 0.0509740 secs]
[GC 101002K->66971K(126720K), 0.0529873 secs]
[GC 101915K->67931K(126720K), 0.0432661 secs]
[GC 102875K->68896K(126720K), 0.0468042 secs]
[GC 103840K->69864K(126720K), 0.0515457 secs]
[GC 104808K->70787K(126720K), 0.0435953 secs]
[GC 105731K->71789K(126720K), 0.0438197 secs]
[GC 106733K->72799K(126720K), 0.0520742 secs]
[GC 107743K->73692K(126720K), 0.0528108 secs]
[GC 108636K->74622K(126720K), 0.0531088 secs]
[GC 109566K->75533K(126720K), 0.0523352 secs]
[GC 110477K->76456K(126720K), 0.0532375 secs]
[GC 111400K->77423K(126720K), 0.0434274 secs]
[GC 112367K->78398K(126720K), 0.0435165 secs]
[GC 113342K->79417K(126720K), 0.0537748 secs]
[GC 114361K->80287K(126720K), 0.0432627 secs]
[GC 115231K->81156K(126720K), 0.0422614 secs]
[GC 116100K->82170K(126720K), 0.0427083 secs]
[GC 117114K->83087K(126720K), 0.0528816 secs]
[GC 118031K->84140K(126720K), 0.0488751 secs]
[GC 119084K->85046K(126720K), 0.0533192 secs]
[GC 119990K->86011K(126720K), 0.0542484 secs]
[GC 120955K->86914K(126720K), 0.0451865 secs]
[GC 121858K->87861K(126720K), 0.0435737 secs]
[GC 122805K->88683K(126720K), 0.0457787 secs]
[GC 123627K->89739K(126720K), 0.0540739 secs]
[Full GC 124683K->59854K(126720K), 0.9496498 secs]
h2. Next Topic: Young Generation Sizing

In the 3rd paragraph you have a link from the phrase "server class machine." The link is incorrect: it has a double-quote at the end of the URL. It should be:

Posted by guest on February 14, 2006 at 06:53 AM EST #

Hi, I like your blog about java performance. Can you please tell me if you know anyway to do profiling on java program via a command line? For example, I would like to do a memory usage between each build. It would be nice if I can kick off a profiling using commandn lines and save the result in a file. And I can write a tool to do comparsion. Is that possible?

Posted by ying on October 18, 2006 at 06:38 PM EDT #

Post a Comment:
  • HTML Syntax: NOT allowed



« April 2014