Skip to main content

Mash that trash -- Incremental compaction in the IBM JDK Garbage Collector

How to minimize pause times and free the heap from dark matter

Aruna Kalagnanam (kaaruna@in.ibm.com), Software Engineer, IBM Global Services, India
Aruna Kalagnanam is a Software Engineer with e-Business Integration Technologies, IBM India Labs. You can contact Aruna at kaaruna@in.ibm.com.
Sripathi Kodi (sripathi@in.ibm.com), Software Engineer, IBM Global Services, India
Sripathi Kodi is a Software Engineer with e-Business Integration Technologies, IBM India Labs. You can contact Sripathi at sripathi@in.ibm.com

Summary:  This article discusses incremental compaction, a new feature in the memory management component of IBM JDK 1.4.0. Incremental compaction is a way of spreading compaction work across different garbage collection cycles, thereby reducing pause times. The authors discuss the need for incremental compaction, the compaction phases at a high level, and some runtime parameters. They also explain how to interpret changes in the verbosegc output.

Date:  01 Jun 2003
Level:  Advanced
Activity:  4370 views

Introduction

Java applications do not have memory management issues, because the garbage collector of the Java Virtual Machine (JVM) takes care of all the storage issues. The garbage collector in the IBM JVM is based on the mark-sweep-compact (MSC) algorithm, where garbage collection (GC) takes place in three phases. At the end of the mark and sweep phases, free space is available, but there is a possibility of heap fragmentation. The compact phase alleviates the fragmentation problem by moving chunks of allocated space towards the lower end of the heap, helping create contiguous free memory at the other end.

Mark-sweep-compaction (MSC) algorithm

MSC, one of the simpler GC algorithms, is used in IBM's JVM and works in three phases:

Mark: Recursively marks all the live objects, starting with the registers and thread stacks.
Sweep: Frees all the objects that were not marked in the mark phase.
Compaction: Optional; it reduces heap fragmentation. This phase attempts to move all live objects to one end of the heap, freeing up large areas of contiguous free space at the other end.

Since the advent of 64-bit operating systems, applications have had the liberty to use large heaps. With Java applications using large heaps, compaction of the heap takes quite a lot of time, during which the application will not be able to do anything else. This period of time is called pause time. Pause times of 40 seconds are quite possible for compaction of a 1 GB heap. Such long pause times are often unacceptable for real-time applications. Incremental compaction (IC) is a way of reducing pause times. IC also reduces the "dark matter" in a heap, which we'll discuss in the next section.


Incremental compaction

Incremental compaction decreases the pause times during compaction by distributing compaction work across different GC cycles. IC also removes dark matter from the heap. Any piece of storage that is more than 512 bytes is treated as free space and is available to mutators or object allocators. Other chunks that are less than 512 bytes are termed dark matter, and are not available as free space.

The amount of dark matter in the heap will directly affect the application throughput, because more dark matter means less free space on the heap for object allocation. This, in turn, will mean more GC cycles seriously affecting the application performance. Incremental compaction aims to minimize pause times, as well as free the heap from dark matter.

The fundamental idea behind incremental compaction is to split the heap up into sections and compact each section just as during a full compaction. IC moves all the moveable objects down the heap, which retrieves all the dark matter and leaves large areas of free space. Individual sections on which IC runs are of fixed size, thereby binding the pause time.


Figure 1. Before and after incremental compaction
Before and after incremental compaction

In the top part of Figure 1 above, marked portions are live objects, and unmarked portions represent free space. There might be dark matter among the free spaces depending on the size of the free chunk, as shown in the diagram. The bottom part of Figure 1 shows the situation after IC. Live objects are moved to one end of the section, freeing up space on the other end.

Incremental compaction is done only if the heap size is at least a constant value, currently 128 MB. If the heap size is less than this, IC fails to provide significant improvement in pause time compared to full compaction. The value of 128 MB has been suggested by performance teams for current conditions.

Incremental compaction cycle

An incremental compaction cycle is successive garbage collection cycles that will incrementally compact the entire heap, a region at a time. There are two main steps to IC:

  • Identify and remember all references that point into the compaction region, which is done during the mark phase. At the end of this stage all free space within the sections can be identified.
  • Compute the new locations of objects and move them within the compaction region, then fix up pointers to those objects.

This section explains the detailed process of incremental compaction.

Regions and sections
A region is a portion of the heap that's subjected to incremental compaction in one cycle. The heap is divided into several regions, and IC runs on one of these regions each time it runs. The whole heap is thus covered in a few GC cycles. Each region is further divided into sections, and IC on each section is handled by one GC helper thread.

Incremental compaction divides each region into (Number of GC helper threads +1) or 8 sections, whichever is less. There is currently a limitation of 16 MB on the size of each section, which limits the size of each region to a maximum of 16 x 8 = 128 MB. IC then makes as many such regions as required to cover the entire heap. Size of each region thus varies with the number of sections, as follows. For:

  • 1 section, region is 16 MB.
  • 2 or 3 sections, region is 32 MB
  • 4, 5, 6, or 7 sections, region is 64 MB
  • 8 sections, region is 128 MB.

Figure 2 below shows the regions in a 256 MB memory running on a 4-CPU machine. In this example, we have four sections per region, and the region size is 64 MB. To divide the heap into regions, IC starts from the lower end of the heap and reaches the higher end. The first and last regions might be less than 64 MB because of rounding to nearest 64 MB boundaries.


Figure 2. Sectioning the heap
Sectioning the heap
Remembering references into the compaction region
Once IC has chosen the region to compact, the rest of the process resembles regular compaction. IC must first remember all references for objects in the compaction region, then fix up those references so they point to proper places after objects are moved. Finally, IC moves the objects within the region.

To remember the references into the compaction region, IC uses a new bit vector called FR_bits (Fixup References bits). This is implemented as a bitmap, having one bit for each reference (valid address) inside the heap. Because references are 4 bytes on 32-bit platforms and 8 bytes in 64, there is one bit in FR_bits for 4 bytes on 32-bit platforms and 1 bit for 8 bytes on 64-bit platforms. While marking references in the mark phase, if IC notices any reference into the compaction region, it sets the corresponding bit in the FR bitmap, because these references will change when IC moves objects within the compaction region.

Break tables
As mentioned earlier, moving objects takes place within sections of the region. For example, each GC helper thread takes care of moving objects within the section given to it. IC uses break tables inside each section to decide how much, and where, to move live objects. See Resources for information on break tables.

There is a separate break table for each section in the region, each being built concurrently by a separate thread. IC walks the section looking for free space and live objects; for each block of live objects it writes a break table entry to record how much all the objects in the block will move by. The break table is big enough to hold 100,000 such entries. If it fills up, IC only compacts the part of the section it has walked so far.

Each entry in the break table is a pair of values, offset from the beginning of the first live object in the section, and shows (in bytes) the amount to move.

Fixing up the references
This is the phase just before we actually move the objects. IC fixes up all references to the objects to be moved before it moves them. The FR_bits are used to find where references are in the compaction region. Break tables tell where the objects are to be moved. The main GC thread first triggers the helper threads to start fixing up references in each section. It then scans the loaded classes in system heaps, other heaps, and primitive classes, and fixes references from these roots to moved objects. Ultimately, the main thread also joins the helper threads in fixing up the references. When the main thread has finished, it waits for all helper threads to finish their work.
Moving the objects
Moving the objects is done one section at a time, and each section is processed by a separate helper thread. IC walks the section, looking for movable objects. The break table tells how much each of these objects can be moved. At the end of this phase, IC rebuilds the free space to include all the free space within each section into a chain of free chunks.

Interpreting verbosegc output

The most commonly used method to analyze what the garbage collector does is running the JVM with the -verbosegc option. This section shows how to interpret verbosegc output corresponding to IC.

The verbosegc example below shows an incremental compaction.


Listing 1. A typical verbosegc output when IC is on
	
<AF[1]: Allocation Failure. need 528 bytes, 0 ms since last AF>
<AF[1]: managing allocation failure, action=1 (0/131070464) (3145728/3145728)>
  <GC(1): GC cycle started Tue Jun 11 14:33:27 2002
  <GC(1): freed 130223768 bytes, 99% free (133369496/134216192), in 1906 ms>
  <GC(1): mark: 444 ms, sweep: 649 ms, compact: 813 ms>
  <GC(1): refs: soft 0 (age >= 32), weak 0, final 3, phantom 0>
  <GC(1): moved 6461 objects, 363840 bytes, IC reason=13>
<AF[1]: completed in 1936 ms>

The line

<GC(1): moved 6461 objects, 363840 bytes, IC reason=13>

shows how many objects have been moved, how many bytes have been moved, and the reason for compaction. The IC reason implies this was an incremental compaction. The possible reasons a.k.a. triggers for a compaction, including IC, are:

1. Following the mark and sweep phase there is insufficient free space for the allocation request.
2. The heap is fragmented and will benefit from an incremental compaction.
3. Less than half the -Xminf value is free space (the default is 30%, which in this case will be less than 15% free space), and the free space plus the dark matter is not less than -Xminf.
4. A System.gc collection.
5. Less than 5% free space available.
6. Less than 128K free space available.
7. The -Xcompactgc parameter has been specified.
8. The transient heap has less than 5% free space available.
10. Incremental compaction is being performed in this GC cycle.
11. Compact to avoid heap shrinkage.
12. An incremental compaction due to excessive dark matter.
13. The -Xpartialcompactgc parameter has been specified.

*It may be noticed that there is no 9 on the list. Trigger 9 was removed as it is no longer being used.

Runtime parameters

There are two runtime parameters available to selectively switch IC on or off:

-Xpartialcompactgc
Run an IC every GC cycle. Default value is false.
-Xnopartialcompactgc
Never run an IC during the life of this JVM. Default value is false.
These parameters are available for testing and debugging purposes, and should not be used in a production environment. Otherwise, IC is ON by default.


Performance improvements

In tests conducted by the performance team, a significant reduction was observed in the GC pause times with IC as compared to without IC. In Figure 3, which shows the results of SPECjbb runs using a JDK 140 build on Z/OS machine with 16 CPUs, we can clearly conclude that the pause times have come down from a high of 10 seconds with IC off to a maximum of 0.5 seconds with IC on. This is a very significant improvement in the performance of the GC with IC, and is a major factor in improving the response times of large Java applications.


Figure 3. SPECjbb results


Resources

About the authors

Aruna Kalagnanam is a Software Engineer with e-Business Integration Technologies, IBM India Labs. You can contact Aruna at kaaruna@in.ibm.com.

Sripathi Kodi is a Software Engineer with e-Business Integration Technologies, IBM India Labs. You can contact Sripathi at sripathi@in.ibm.com

Comments (Undergoing maintenance)



Trademarks  |  My developerWorks terms and conditions

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Sample IT projects
ArticleID=10269
ArticleTitle=Mash that trash -- Incremental compaction in the IBM JDK Garbage Collector
publish-date=06012003
author1-email=kaaruna@in.ibm.com
author1-email-cc=
author2-email=sripathi@in.ibm.com
author2-email-cc=

My developerWorks community

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere).

My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).