Saturday, January 12, 2013

short notes on how java garbage collection works (for my personal use)


this is just an extract from my research (?) on java garbage collection. contains discrete and unorganized notes.
these are mostly from


http://www.oracle.com/technetwork/java/gc-tuning-5-138395.html#1.1.%20Generations|outline
https://book.dynatrace.com/content/memory/reduce-garbage-collection-pause-time.aspx
http://chaoticjava.com/posts/how-does-garbage-collection-work/
http://www.oracle.com/technetwork/java/javase/gc-tuning-6-140523.html



-verbose:gc prints information at every collection
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps will additionally print a time stamp at the start of each collection


collections occur when generations fill up, throughput is inversely proportional to the amount of memory available. Total available memory is the most important factor affecting garbage collection performance.

-XX:MinHeapFreeRatio=<minimum>
-XX:MaxHeapFreeRatio=<maximum>

With these parameters if the percent of free space in a generation falls below <minimum>%, the size of the generation will be expanded so as to have <minimum>% of the space free, assuming the size of the generation has not already reached its limit.

Similarly, if the percent of free space exceeds <maximum>%, the size of the generation will be shrunk so as to have only <maximum>% of the space free as long as shrinking the generation does not decrease it below the minimum size of the generation.

the young generation size is controlled by NewRatio. For example, setting
-XX:NewRatio=3 means that the ratio between the young and tenured generation is 1:3.

The parameters NewSize and MaxNewSize bound the young generation size from below and above. Setting these equal to one another fixes the young generation, just as setting -Xms and -Xmx equal fixes the total heap size.

When there isn't enough memory available in the tenured generation for this worst case, a major collection will occur instead.

-XX:SurvivorRatio=6 sets the ratio between each survivor space and eden to be 1:6. In other words, each survivor space will be one eighth of the young generation (not one seventh, because there are two survivor spaces).

If survivor spaces are too small, copying collection overflows directly into the tenured generation. If survivor spaces are too large, they will be uselessly empty. At each garbage collection the virtual machine chooses a threshold number of times an object can be copied before it is tenured. This threshold is chosen to keep the survivors half full.

-XX:+PrintTenuringDistribution, can be used to show this threshold and the ages of objects in the new generation.

The discussion to this point has been about the serial collector.


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 serial collector.

The concurrent low pause collector: this collector is used if the -Xincgc ™ or -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.

Note that -XX:+UseParallelGC should not be used with -XX:+UseConcMarkSweepGC

throughput collector ->

Use the throughput collector when you want to improve the performance of your application with larger numbers of processors. The throughput collector is a generational collector similar to the serial collector but with multiple threads used to do the minor collection. The major collections are essentially the same as with the serial collector.

-XX:ParallelGCThreads=<desired number>
The maximum pause time goals is specified with the command line flag
-XX:MaxGCPauseMillis=<nnn>

-XX:GCTimeRatio=<nnn>

The ratio of garbage collection time to application time is

1 / (1 + <nnn>)
For example -XX:GCTimeRatio=19 sets a goal of 5% of the total time for garbage collection. By default the goal for total time for garbage collection is 1%.

Growing and shrinking the size of a generation is done by increments that are a fixed percentage of the size of the generation. By default a generation grows in increments of 20% and shrinks in increments of 5%.

The percentage for growing is controlled by the command line flag -XX:YoungGenerationSizeIncrement=<nnn > for the young generation and -XX:TenuredGenerationSizeIncrement=<nnn>

The throughput collector will throw an out-of-memory exception if too much time is being spent doing garbage collection.


concurrent low pause collector ->

Use the concurrent low pause collector if your application would benefit from shorter garbage collector pauses and can afford to share processor resources with the garbage collector when the application is running.

The concurrent low pause collector is a generational collector similar to the serial collector. The tenured generation is collected concurrently with this collector.

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.



If the garbage collector has become a bottleneck, you may wish to customize the generation sizes.

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.


The rules of thumb for server applications are:

First decide the total amount of memory you can afford to give the virtual machine. Then graph your own performance metric against young generation sizes to find the best setting.

Unless you find problems with excessive major collection or pause times, grant plenty of memory to the young generation.

Increasing the young generation becomes counterproductive at half the total heap or less (whenever the young generation guarantee cannot be met).

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


How can I increase the permanent generation size?

Use the command line option -XX:MaxPermSize=<desired size>


    How do I know what classes are being loaded or unloaded?


Use the command line options -XX:+ TraceClassloading and -XX:+ TraceClassUnloading



Use the -XX option MaxTenuringThreshold to determine the copying costs. Use -XX:MaxTenuringThreshold=0 to move an object that survives a young generation collection immediately to the tenured generation. Note that the throughput collector does not use the MaxTenuringThreshold parameter.

The Concurrent Mark Sweep (CMS) collector (also referred to as the concurrent low pause collector) collects the tenured generation. It attempts to minimize the pauses due to garbage collection by doing most of the garbage collection work concurrently with the application threads.

Normally the concurrent low pause collector does not copy nor compact the live objects. A garbage collection is done without moving the live objects.f fragmentation in the tenured generation becomes a problem, a compaction of the tenured generation will be done although not concurrently. In 1.4.1 that compaction will occur if the UseCMSCompactAtFullCollection option is turned on.

-XX:+UseCMSCompactAtFullCollection

What are the phases of the concurrent low pause collector?


There are six phases involved in the collection:


Phase 1 (Initial Checkpoint) involves stopping all the Java threads, marking all the objects directly reachable from the roots, and restarting the Java threads.


Phase 2 (Concurrent Marking) starts scanning from marked objects and transitively marks all objects reachable from the roots. The mutators are executing during the concurrent phases 2, 3, and 5 below and any objects allocated in the CMS generation during these phases (including promoted objects) are immediately marked as live.


Phase 3: During the concurrent marking phase mutators may be modifying objects. Any object that has been modified since the start of the concurrent marking phase (and which was not subsequently scanned during that phase) must be rescanned. Phase 3 (Concurrent Precleaning) scans objects that have been modified concurrently. Due to continuing mutator activity the scanning for modified cards may be done multiple times.


Phase 4 (Final Checkpoint) is a stop-the-world phase. With mutators stopped the final marking is done by scanning objects reachable from the roots and by scanning any modified objects. Note that after this phase there may be objects that have been marked but are no longer live. Such objects will survive the current collection but will be collected on the next collection.

Phase 5 (Concurrent Sweep) collects dead objects. The collection of a dead object adds the space for the object to a free list for later allocation. Coalescing of dead objects may occur at this point. Note that live objects are not moved.

Phase 6 (Resetting) clears data structures in preparation for the next collection.


What is the Parallel Young Generation collector (-XX:+UseParNewGC)?


The parallel young generation collector is similar to the parallel garbage collector (-XX:+UseParallelGC) in intent and differs in implementation. Most of the above description for the parallel garbage collector (-XX:+UseParallelGC) therefore applies equally for the parallel young generation collector. Unlike the parallel garbage collector (-XX:+UseParallelGC) this parallel young generation collector can be used with the concurrent low pause collector that collects the tenured generation.


If you're using RMI (remote method invocation), then you could be running into distributed garbage collection (GC). Also, some applications are adding explicit GC's thinking that it will make their application faster. Luckily, you can disable this with an option available in version 1.3 and 1.4. Try -XX:+ DisableExplicitGC along with -verbose:gc and see if this helps.


A concurrent collection starts running when the percentage of allocated space in the old generation crosses a threshold. This threshold is calculated based on general experience with the concurrent collector. If full collections are occurring, the concurrent collections may need to be started earlier. The command line flag CMSInitiatingOccupancyFraction can be used to set the level at which the collection is started. Its default value is approximately 68%. The command line to adjust the value is

-XX:CMSInitiatingOccupancyFraction=<percent>





What are the default settings for the concurrent low pause collector?

The default heap size for the concurrent low pause collector is the same as for the default collector. The other parameters are set a described below. These setting have been shown to work well for an application that has mostly very short lived data plus some data that is very long lived. Some of the options require a computation which is enclosed in angle brackets (<>), of which two depend on the number of cpus on the machine (#cpus.)

# enable the concurrent low pause collector

-XX:+UseConcMarkSweepGC



# use parallel threads

-XX:+UseParNewGC

-XX:ParallelGCThreads=<#cpus < 8 ? #cpus : 3 + ((5 * #cpus) / 8) >

-XX:+CMSParallelRemarkEnabled



# size young generation for short pauses

-XX:NewSize=4m

-XX:MaxNewSize=< 4m * ParallelGCThreads >



# promote all live young generation objects

-XX: MaxTenuringThreshold=0

-XX:SurvivorRatio=1024


It is also recommended that a heap size be used that is 20-30% larger than that which would be used with the default collector.



[GC [<collector>: <starting occupancy1> -> <ending occupancy1>, <pause time1> secs] <starting occupancy3> -> <ending occupancy3>, <pause time3> secs]


where

<collector> is an internal name for the collector used in the minor collection

<starting occupancy1> is the occupancy of the young generation before the collection

<ending occupancy1> is the occupancy of the young generation after the collection

<pause time1> is the pause time in seconds for the minor collection.

<starting occupancy3> is the occupancy of the entire heap before the collection

<ending occupancy3> is the occupancy of the entire heap after the collection

<pause time3> is the pause time for the entire garbage collection. This would include the time for a major collection is one was done.


http://www.oracle.com/technetwork/java/gc-tuning-5-138395.html#1.1.%20Generations|outline
https://book.dynatrace.com/content/memory/reduce-garbage-collection-pause-time.aspx

No comments:

Post a Comment