Thursday, 3 November 2011

About Garbage Collection

 

Frequently Asked Questions
about Garbage Collection
in the HotspotTM JavaTM Virtual Machine

This document describes the behavior of the Java(tm) HotSpot(tm) virtual machine. This behavior is not part of the VM specification, however, and is subject to change in future releases. Moreover the behavior described here is generic behavior and will not apply to the execution of all Java applications.

1.      How is the generational collector implemented in HotSpot(tm)?

The default collector in HotSpot has two generations: the young generation and the tenured generation. Most allocations are done in the young generation. The young generation is optimized for objects that have a short lifetime relative to the interval between collections. Objects that survive several collections in the young generation are moved to the tenured generation. The young generation is typically smaller and is collected more often. The tenured generation is typically larger and collected less often.

The young generation collector is a copying collector. The young generation is divided into 3 spaces: eden-space, to-space, and from-space. Allocations are done from eden-space and from-space. When those are full a young generation is collection is done. The expectation is that most of the objects are garbage and any surviving objects can be copied to to-space. If there are more surviving objects than can fit into to-space, the remaining objects are copied into the tenured generation. There is an option to collect the young generation in parallel.

The tenured generation is collected with a mark-sweep-compact collection. There is an option to collect the tenured generation concurrently.

2.      What is the relevance of -XX:MaxNewSize? Where will the differences between -XX:NewSize and -XX:MaxNewSize grow, Eden or Survivor Spaces?

The young generation is set by a policy that bounds the size from below by NewSize and bounds it from above by MaxNewSize. As the young generation grows from NewSize to MaxNewSize, both eden and the survivor spaces grow.

3.      Are all eden-space objects moved into the survivor space so that after a minor gc, eden-space is empty?

Yes. If all the live objects in eden do no fit into a survivor space, the remaining live objects are promoted into the old generation.

4.      When using -XX:TargetSurvivorRatio=90 will this leave ten percent of to-space for objects to be moved from eden?

No. It means that a tenuring threshold is chosen so that, based on the ages of what was scavenged in the last minor collection, there should be nearly 90% of the survivor size used. The actual amount scavenged from either the survivor space or eden may be considerably more or less.

TargetSurvivorRatio does not usually make a big difference.
5.      If objects in eden-space require more space than is available in the to-survivor space, will eden-space objects have precedence over from-survivor space objects? How does the age of from-survivor space objects affect promotion?

There is no distinction here between what comes from eden and what comes from the from-survivor space. After a minor collection completes, both eden and the from-survivor space are empty. If the to-survivor space fills up, any remaining objects are promoted directly into the old generation regardless of their age or origin.


6.      Between NewSize and NewRatio which option takes precedence?
In jdk 1.4.1 and later, neither has strict precedence. The maximum of NewSize and the size calculated using NewRatio is used. The formula is

min(MaxNewSize, max(NewSize, heap/(NewRatio+1)))

7.      How should the permanent generation be sized?
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.

8.      How can I tell if the permanent generation is filling up?

Starting in 1.4.2 -XX:+PrintGCDetails will print information about all parts of the heap collected at each garbage collection. For a full collection

[Full GC [Tenured: 30437K->33739K(280576K), 0.7050569 secs] 106231K->33739K(362112K), [Perm : 2919K->2919K(16384K)], 0.7052334 secs]

this example shows that little was collected in the permanent generation (it went from 2919K used before the collection to 2919K used after the collection) and the current size of the permanent generation is 16384K.

9.      How can I increase the permanent generation size?

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

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

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

11.  What is the best size for the young generation?

The young generation should be sized large enough so that short-lived objects have a chance to die before the next young generation collection. This is a tradeoff since a larger young generation will allow more time for objects to die but may also take longer to collect. Experiment with the size of the young generation to optimize the young generation collection time or the application throughput.


19.  Can I see how much of a thread allocation buffer is being left unused?

There's a flag, -XX:+PrintTLAB,that will trace all the operations on TLAB's. In particular, it prints lines like

reset TLAB: thread: 0x0002d7d0 size: 8KB unused: 76B Total fragmentation 0.004499

each time a TLAB is filled with a int[]. In this case, the unused trailing 76B will be unused.

This is an example of a TLAB that has filled up and a new one will be allocated. The amount of waste here is relatively small. More waste can occur in preparation for a garbage collection. For TLAB output that show up just before the a garbage collection like

reset TLAB: thread: 0x0002d840 size: 8KB unused: 7276B Total fragmentation 0.004580
[Full GC 10424K->591K(15688K), 0.1222677 secs]

where we are filling 7276 bytes of the 8192 byte TLAB. (The "Total fragmentation" is a cumulative accounting of the fragmentation caused by TLAB's.) TLAB's resize by default on SPARC -server, or if you use the -XX:+ResizeTLAB flag, so you may well get large TLAB's if you are running that JVM. Note that we aren't "wasting" the space for the fillers right before collections, as the collection will recover the space the filler objects occupy.

20.  Does the default of NewRatio change with the compiler?

On SPARC's, -XX:NewRatio defaults to 8 with -client and 2 with -server, so the ratio of the young generation to the old generation will be 1::8 and the young generation will be 1/9th of the heap in -client and 1::2 or 1/3rd of the heap with -server.


30.  Should I increase the size of the permanent generation in the client vm?

This will always be a judgment call. In general increasing the size of a generation (and this applies not just to the permanent generation) can reduce the incidence of a wide variety of problems However, this may cause other processes to excessively page and/or garbage collect or throw out-of-memory exceptions.

There are two failure modes to consider.

When raising MaxPermSize, it is possible that previously well behaved programs that used to garbage collect to recover the permanent generation space will die by endless paging. For the permanent generation this usually only happens with the heavy interning of temporary strings.

The other failure mode is that address space must be reserved for the permanent generation and this will reduce that available for the rest of the heap (the maximum -Xmx may then be too large). This will cause programs configured to use all available space to fail at initialization.

Permanent generation defaults in recent VM's.

Release

v1.3.1_06
v1.4.1_01
v1.4.2
Client
PermSize
1M
4M
4M
Server
PermSize
1M
4M
16M
Client
MaxPermSize
32M
64M
64M
Server
MaxPermSize
64M
64M
64M


31.  Should I pool objects to help GC? Should I call System.gc() periodically?

The answer to these is No!

Pooling objects will cause them to live longer than necessary. We strongly advise against object pools.

Don't call System.gc(). The system will make the determination of when it's appropriate to do garbage collection and generally has the information necessary to do a much better job of initiating a garbage collection. If you are having problems with the garbage collection (pause times or frequency), consider adjusting the size of the generations.

No comments:

Post a Comment