Skip to Content

How to optimize memory usage

Printer-friendly versionSend to friendPDF version
Expert

The first thing said when reading books on Java application is that developers "do not need to worry about memory usage".

It's said that:

  • A Java developer don't have to write specific Java code for freeing used object like in C or C++ languages
  • The JVM is responsible for the memory management

But most of the time, applications in production face some critical issues related to memory usage.

Why?

Because, although it's not a developer responsibility to worry about memory usage in the core code of the application, it is his responsibility to understand how a JVM and the garbage collector is working and what should be tuned to meet the best performances on the dedicated platform.

Tuning a Java application is not an easy step, it will depend on your hardware but it is also necessary to have a predictable system in production.

Before trying to tune memory usage it is important to troubleshoot memory leaks in application code.

What should be known?

How a JVM is implemented?

A JVM is divided in 3 different principle spaces:

  • The Young
    1. Eden

      This space in the Object Heap is responsible for new allocated objects.

    2. Survivors: S1 and S2

      When the Eden is full, a minus GC is launched on the Eden space and all the objects still in life are saved in one of the surviving spaces.

      When objects in the survivor have survived to a certain amount of minus GC they are saved in Tenured part of the VM.

  • The Tenured (or Old)

    The old generation region contains objects that were previously compacted by the garbage collector.

    When the all memory (Old and Young) is full a "full garbage collecting" is launched on the entire VM.

  • The Permanent

    The permanent generation is used to hold reflective of the VM itself such as class objects and method objects. These reflective objects are allocated directly into the permanent generation, and it is sized independently from the other generations. Generally, sizing of this generation can be ignored because the default size is adequate. However, programs that load many classes may need a larger permanent generation.

What is Garbage Collecting and how does it work?

The Garbage Collecting is a JVM task responsible to free unused objects in the JVM, there are different implementations of the garbage process.

Within each heap area, the CLDC HotSpot Implementation virtual machine employs a two-generational mark-and-compact garbage collector, as illustrated in FIGURE 3-1.

 

 

The object heap is divided into old generation, new generation, and as-yet-unused portions of memory. The old generation region contains objects that were previously compacted by the garbage collector. New objects are allocated in the new generation region, which is generally much smaller. When the new generation region is full, the garbage collector runs briefly and reclaims the unused memory for that generation. In this case, the former new generation becomes part of the "new" old generation. A part of the unused portion of the heap is allocated to become the "new" new generation.

When all memory in the object heap is consumed, the garbage collector runs across the entire heap and compacts all live objects into a single "new" old generation. Only during this large garbage collection does a longer pause occur, but it occurs infrequently.

This scheme takes advantage of the fact that the vast majority of objects are short lived. Because most objects are short lived, only a small portion of allocated objects are promoted to the old generation. Most garbage collection operations focus only on the new generation, resulting in only very small garbage collection pauses.

 

JVM monitoring Tools and troubleshooting tools

  • -verbose:gc : causes information about the heap and garbage collection to be printed at each collection

    [GC 325407K->83000K(776768K), 0.2300771 secs]

    [GC 325816K->83372K(776768K), 0.2454258 secs]

    [Full GC 267628K->83769K(776768K), 1.8479984 secs]

  • -XX:+PrintGCDetails and -XX:+PrintGCTimeStamps : can add some more detail informations

    [GC [DefNew: 64575K->959K(64576K), 0.0457646 secs] 196016K->133633K(261184K), 0.0459067 secs]

    111.042: [GC 111.042: [DefNew: 8128K->8128K(8128K), 0.0000505 secs]111.042: [Tenured: 18154K->2311K(24576K), 0.1290354 secs] 26282K->2311K(32704K), 0.1293306 secs]

  • jstat -gcutil <Java PID> <Time in Milli Sec> : Gives information of the % of usage of each part of the VM, number og Garbage Collection, and time spent on collection
    S0 S1 E O P YGC YGCT FGC FGCT GCT

    12.44 0.00 27.20 9.49 96.70 78 0.176 5 0.495 0.672

    12.44 0.00 62.16 9.49 96.70 78 0.176 5 0.495 0.672

  • visualgc : Visual Garbage Collection Monitoring Tool - a graphical tool for monitoring the HotSpot Garbage Collector, Compiler, and class loader. It can monitor both local and remote JVMs
  • jmap -histo <java pid> : prints a histogram of the heap
  • jstack <java pid> : prints Java stack traces of Java threads for a given Java process or core file or a remote debug server

 

Tuning considerations and recommendations

  • The JVM Size on JVM 32 bit can't be greater than 4Go.
  • Permannent Generation space is not part of the Heap.
  • Heap size is the sum of the New Generation and the Old Generation.
  • Young Generation is the sum of the Eden and the Survivors spaces.
  • Before trying to tune be sure to have avoided any memory issues like memory "dead locks".
  • The JVM size should be less than the physical memory of the server to avoid any access on disk.
  • Take into account each component of the application which should grow closely to the usage (connections or objects pools).
  • Minor collections should appear frequentely and should be fast.
  • Major collections should appear less and will take much time.

 

Tuning options

JVM Sizing

Tuning Java launcher options:

  • -server : Select the Java HotSpot Server VM
  • -Xssn: Set thread stack size. Could be changed for an aplication which uses a lot of threads or has a little amount of memory.

Total Heap

  • -Xmx : Specify the maximum size, in bytes, of the memory allocation pool. This value must a multiple of 1024 greater than 2MB. Append the letter k or K to indicate kilobytes, or m or M to indicate megabytes.
  • -Xms : Specify the initial size, in bytes, of the memory allocation pool. This value must be a multiple of 1024 greater than 1MB. Append the letter k or K to indicate kilobytes, or m or M to indicate megabytes. The default value is 2MB.

    Xms and Xmx should be set at the same value on a production server !

  • -XX:MinHeapFreeRatio
  • -XX:MaxHeapFreeRatio
  • -XX:SurvivorRatio
  • -XX:NewRatio

    Unless you have problems with pauses, try granting as much memory as possible to the virtual machine. The default size (64MB) is often too small.

    Setting -Xms and -Xmx to the same value increases predictability by removing the most important sizing decision from the virtual machine. On the other hand, the virtual machine can't compensate if you make a poor choice.

    Be sure to increase the memory as you increase the number of processors, since allocation can be parallelized.

Performance options

  • -XX:MaxPermSize : Size of the Permanent Generation.
  • -XX:+AggressiveOpts : Turn on point performance compiler optimizations that are expected to be default in upcoming releases. (Introduced in 5.0 update 6.)

Garbage Collecting

Three types of collectors :

  • The throughput collector: this collector uses a parallel version of the young generation collector. It is used if the -XX:+UseParallelGC option is passed on the command line. The tenured generation collector is the same as the default collector.
  • The concurrent low pause collector: this collector is used if the -XX:+UseConcMarkSweepGC is passed on the command line. The concurrent collector is used to collect the tenured generation and does most of the collection concurrently with the execution of the application. The application is paused for short periods during the collection. A parallel version of the young generation copying collector is used with the concurrent collector (i.e. if -XX:+UseConcMarkSweepGC is used on the command line then the flag UseParNewGC is also set to true if it is not otherwise explicitly set on the command line).
  • The incremental low pause collector: this collector is used only if -Xincgc is passed on the command line. By careful bookkeeping, the incremental garbage collector collects just a portion of the tenured generation at each minor collection, trying to spread the large pause of a major collection over many minor collections. However, it is even slower than the default tenured generation collector when considering overall throughput.
  1. throughput collector

    -XX:+UseParallelGC : enable parallelGC

    -XX:ParallelGCThread : define number of threads

    Turning on the throughput collector should just make the minor collection pauses shorter. Because there are multiple garbage collector threads participating in the minor collection there is a small possibility of fragmentation due to promotions from the young generation to the tenured generation during the collection.

  2. concurrent low pause collector

    -XX:+UseConcMarkSweepGC

    This collector attempts to reduce the pause times needed to collect the tenured generation. It uses a separate garbage collector thread to do parts of the major collection concurrently with the applications threads.

  3. incremental low pause collector

    -XX:+UseConcMarkSweepGC

    -XX:+CMSIncrementalMode

    -XX:+CMSIncrementalPacing

    -XX:CMSIncrementalDutyCycleMin=0

    -XX:+CMSIncrementalDutyCycle=10

    The concurrent collector can be used in a mode in which the concurrent phases are done incrementally. Recall that during a concurrent phase the garbage collector thread is using a processor. The incremental mode is meant to lessen the impact of long concurrent phases by periodically stopping the concurrent phase to yield back the processor to the application.

Want more?

Sun FAQ on garbage collecting

JVM Garbage Collecting Tuning guide for eachVersion
1.6
1.5
1.4.2

JVMStat Tools

JDK Tools and Utilities

Java application launcher

JVM Tuning parameters

Share this