- Java Reference Guide
- Overview
- Table of Contents
- J2SE: Standard Java
- Java Windows NT Services
- Apache Velocity
- Advanced J2SE
- Bytecode Instrumentation
- Dynamic Languages and the JVM
- J2SE 1.5.0: "Tiger"
- Ease of Use and Presentation Features
- Variable Arguments
- Desktop Client
- JSRs
- Adaptive Garbage Collection
- Official Documentation
- Java SE 6
- Java 7
- Core Computer Science Principles in Java (Data Structures)
- Annotations
- Java Generics
- Java New I/O
- Java Sound
- Java Applets
- JavaFX
- Java SE Threading
- Resource Management Using Semaphores
- Java Atomic Operations
- JavaTemplate Pages
- Executing Templates with the JtpExecutor
- Java Cryptography Extensions (JCE)
- Java Database Connectivity (JDBC) API
- Jakarta Commons - Net Class Library
- Jakarta Commons HttpClient
- Apache POI
- Regular Expressions
- JavaMail
- Cool Tools
- Building an Really Simple Syndication (RSS) Java App
- Embedding JavaScript in Java with Rhino
- Logging with Log4J
- Inside Swing
- Swing Components
- SwingX
- Swing Styled Documents
- Web Rendering in Java Swing Applications
- Java Look-and-Feel Graphics Repository
- Java Media Framework
- Quicktime for Java
- Media in Java Review 2008
- External Multimedia in Java
- Graphs and Charts
- Holiday Special: Electronic Greeting Card
- Media Framework: Presenter Application
- Standard Widget Toolkit
- JFace
- Java Performance Tuning
- J2EE Performance Tuning
- Caches and Pools
- Java Caching System
- EHCache
- Java Compression and Decompression
- Obfuscating Java Applications
- Continuous Integration
- Load Testing
- Tomcat Clustering
- High Scalability with Terracotta
- Troubleshooting Production Performance Issues
- Enterprise Java Testing
- Automated Unit Testing with JUnit and Ant
- Unit Testing: Tips From The Trenches
- Custom Ant Tasks
- Extensible Markup Language (XML)
- Java Web Technologies
- Web Frameworks
- Struts 2
- Wicket
- JavaServer Faces
- Distributed Programming / RMI
- Behavior Tracking Servlet Filter
- Servlet Filters
- Building a Robust Java Server
- J2EE: Enterprise Java
- Spring
- Spring 3
- Java Design Patterns
- Model-Driven Architecture
- Enterprise Messaging with ActiveMQ
- Event-Driven Architecture
- XDoclet
- Hibernate
- Developing Standalone Database Applications with Hypersonic DB
- Project Backup
- J2EE Project: Hands-On
- Enterprise Java Beans (EJB) 3.0
- Disaster Recovery
- Java Management Extensions (JMX)
- Service-Oriented Architecture
- Web Services
- RESTful Web Services
- Web Services with Apache CXF
- Atom Syndication
- Project: Building a Web Photo Gallery
- J2ME: Micro Java
- Specialized J2ME
- Optional Packages
- Other Java Technologies
- Derivatives and Competitors
- Java, Engineered for Integration
- Additional Resources
- The World of Java Tools
- Building Java Applications with Ant
- Managing Java Build Lifecycles with Maven
- Acceptance Testing with FitNesse
- Source Control with Subversion
- Inversion of Control and Dependency Injection
- Certification
- Roadmap: Becoming an Enterprise Java Developer
- Roadmap: Becoming an Enterprise Java Developer in 2007
- The Business of Enterprise Software
- JavaOne 2006
- JavaOne 2007
- JavaOne 2008 Wrap-Up
- JavaOne 2009 Wrap-Up
- JavaOne 2010
- JavaOne 2011
- How to Survive in a Turbulent Job Market
- How to Hire the Best Talent
- Unified Modeling Language (UML)
- Cloud Computing
- Amazon EC2 and Java
- MongoDB
- Enterprise Java in 2008 and Beyond
- Predictions for 2018
Adaptive Garbage Collection
Last updated Mar 5, 2004.
Prior to version 1.5 of the JVM, much of a programmer's performance tuning time was spent in properly sizing the various "compartments" of the heap. If this is a new subject to you, consider the following a very brief primer on heap tuning:
The configuration of the heap is different for different vendor implementations. Thus, tuning the Sun JVM, IBM JVM, and BEA JRockit JVM are all different. For the purposes of this discussion, I will docus on the Sun JVM. The Sun JVM heap, hitherto referred to simply as the "heap," is divided into two regions, referred to as generations:
Young Generation
Old Generation
The young generation is further divided into three subregions:
Eden
Survivor Space 1
Survivor Space 2
Objects are created in Eden (yes, as in the Garden of Eden), and hopefully they are destroyed in Eden. When Eden becomes full, the object is moved to the first survivor space; when that becomes full it is moved to the second survivor space; finally, objects that are not destroyed in the second survivor space are retired to the old generation.
The premise is that most objects should be created and destroyed in a relatively short interval, which is the case for most client applications and some server applications.
Garbage collection runs periodically (as needed) with the purpose of locating objects that are no longer referenced. When it finds one, it marks the memory that the object had used as available. The process of running through any of the three regions in the young generation searching for "garbage" is called a minor collection and is relatively painless for the JVM; it can search the regions independently, and each is relatively small. The process of running through the old generation however, is a painful experience that not only takes a long time to run, but brings everything running in the heap to a complete stop. An improperly tuned heap running in a J2EE environment can bring the entire server to a stop for more than a minute every couple minutes; how would your boss react to a Web server that took 90 seconds to respond on a regular basis?!
Garbage collection is one of Java's biggest benefits, but if not used cautiously, it can be one of its biggest limitations. The two characteristics that affect garbage collection performance are:
Pause: the amount of time that the JVM pauses while performing garbage collection
Throughput: the ratio of garbage collection time to application time
The goal is to minimize the pause and maximize the throughput. Yet, there is a tradeoff in defining the sizes of each region: the larger the region, the less frequently it needs to be collected, but the longer each collection will take. In previous versions of the JVM, we used to specify the respective sizes of the young generation's three regions and old generation, load test the application with representative transactions, and observe the behavior of the heap. The desired pattern is a slow build-up of memory usage in the heap to a critical mass, and then a stabilization where sequential minor collections can be observed.
As a general starting point for tuning an enterprise application I recommend the following:
Size the young generation a little less than half the size of the heap. It must be less than half the size of the entire heap by definition, but not much smaller!
Size Eden to be somewhere between one half and two thirds the size of the young generation
Size each survivor space to be between one quarter and one eighth the size of the young generation
The process continues by "testing and tweaking" until things look good.
The 1.5.0 JVM garbage collection has been updated in several ways to address the problems with garbage collection directly. It defines an adaptive sizing policy that will dynamically resize the heap and its respective regions with the following goals:
Adhere to a desired maximum garbage collection pause
Adhere to a desired application throughput goal
Minimize the footprint of the heap
To accomplish this you must enable the adaptive sizing policy by passing the JVM the following argument:
-XX:+UseAdaptiveSizePolicy
To define the desired policy values, use the following flags:
-XX:MaxGCPauseMillis=nnn |
A hint to the virtual machine that pause times of nnn milliseconds or less are desired. The vm will adjust the java heap size and other gc-related parameters in an attempt to keep gc-induced pauses shorter than nnn milliseconds. Note that this may cause the vm to reduce overall throughput, and in some cases the vm will not be able to meet the desired pause time goal. |
-XX:GCTimeRatio=nnn |
The ratio of GC time to application time. 1 / (1 + nnn) For example: XX:GCTimeRatio=19 sets a goal of 5% of the total time for GC. |
So, rather than spending your time trying to manually adjust your heap parameters to meet performance expectations, you can instead ask the heap to adjust itself at runtime to meet those same performance expectations on your behalf.
The feature is in place, but we must still wait to see if it delivers on its promise. Currently, no application servers support version 1.5 of the J2SE. Once we have a valid test environment, we can setup load tests and see how the JVM holds up.
Summary
In this article we have discussed some of the new ease of use and presentation features of the new Java 2 Standard Edition, version 1.5:
Generic Types
Enhanced For Loops
Autoboxing
Enumerated Types
Formatted Input and Output
Variable Arguments
New Look-and-feels
Next we looked at how garbage collection has been greatly improved in Tiger and look forward to a good testing environment where we can validate their claims.
In the next installment we will look deeper under-the-hood of Tiger and see the new management interfaces as well as the new facilities for meta-data.


