Java Virtual Machine
JVM runs as an application on top of an operating system.
JVM effectively reproduce Operating system environment for Java programs.
That’s why it is called Java Virtual machine. The main purpose of JVM is to
convert the Java bytecode to the machine instructions that can execute on the
hardware platform.
Architecture of the Java Virtual Machine
When a JVM runs a program, it needs memory to store many
things including bytecodes and other information it extracts from loaded class
files, objects, parameters to the methods, local variables, return values and
many.
The JVM organizes the memory it needs to execute a program
into several runtime data areas.
Class Loader Subsystem
It is mainly responsible for three activities.
·
Loading
·
Linking
·
Initialization
Loading: The Class loader reads the .class file, generate the
corresponding binary data and save it in method area. For each .classfile, JVM stores following
information in method area.
·
Fully
qualified name of the loaded class and its immediate parent class.
·
Whether .class file is related to
Class or Interface or Enum
·
Modifier,
Variables and Method information etc.
After loading .class file, JVM creates an
object of type Class to represent this file in the heap memory. Please note
that this object is of type Class predefined in java.lang package. This Class
object can be used by the programmer for getting class level information like
name of class, parent name, methods and variable information etc. To get this
object reference we can use getClass() method
of Object class.
Linking: Performs verification, preparation, and (optionally) resolution.
·
Verification: It ensures the correctness of .class file i.e. it check whether this file is
properly formatted and generated by valid compiler or not. If verification
fails, we get run-time exception java.lang.VerifyError.
·
Preparation: JVM allocates memory for class variables and initializing
the memory to default values.
·
Resolution: It is the process of replacing symbolic references from
the type with direct references. It is done by searching into method area to
locate the referenced entity.
Initialization: In this phase, all static variables are assigned with
their values defined in the code and static block(if any). This is executed
from top to bottom in a class and from parent to child in class hierarchy.
In general, there are three class loaders:
In general, there are three class loaders:
·
Bootstrap class loader: Every JVM implementation must have a bootstrap class
loader, capable of loading trusted classes. It loads core java API classes
present in JAVA_HOME/jre/lib directory.
·
Extension class loader: It is child of bootstrap class loader. It loads the
classes present in the extensions directories JAVA_HOME/jre/lib/ext(Extension
path) or any other directory specified by the java.ext.dirs system property. It
is implemented in java by the sun.misc.Launcher$ExtClassLoader class.
·
System/Application class loader: It is child of extension class loader. It is responsible
to load classes from application class path. It internally uses Environment
Variable which mapped to java.class.path.
JVM Memory
Method area: In method area, all class level information like class name, immediate parent class name, methods and variables information etc. are stored, including static variables. There is only one method area per JVM, and it is a shared resource.
Method area: In method area, all class level information like class name, immediate parent class name, methods and variables information etc. are stored, including static variables. There is only one method area per JVM, and it is a shared resource.
Heap
area: Information of all objects is stored
in heap area. There is also one Heap Area per JVM. It is also a shared
resource.
Stack
area: For every thread, JVM create one
run-time stack which is stored here. Every block of this stack is called
activation record/stack frame which store methods calls. All local variables of
that method are stored in their corresponding frame. After a thread terminate,
it’s run-time stack will be destroyed by JVM. It is not a shared resource.
PC
Registers: Store address of current execution
instruction of a thread. Obviously, each thread has separate PC Registers.
Native
method stacks: For every thread, separate native
stack is created. It stores native method information.
Execution Engine
Execution engine execute the .class (bytecode). It reads the byte-code line by line, use data and information present in various memory area and execute instructions. It can be classified in three parts: -
Execution engine execute the .class (bytecode). It reads the byte-code line by line, use data and information present in various memory area and execute instructions. It can be classified in three parts: -
·
Interpreter: It interprets the bytecode line by
line and then executes. The disadvantage here is that when one method is called
multiple times, every time interpretation is required.
·
Just-In-Time
Compiler (JIT): It is
used to increase efficiency of interpreter. It compiles the entire bytecode and
changes it to native code so whenever interpreter see repeated method calls,
JIT provide direct native code for that part so re-interpretation is not
required, thus efficiency is improved.
·
Garbage
Collector: It destroy
un-referenced objects.
Java Native Interface (JNI)
It is a interface which interacts with the Native Method Libraries and provides the native libraries (C, C++) required for the execution. It enables JVM to call C/C++ libraries and to be called by C/C++ libraries which may be specific to hardware.
It is a interface which interacts with the Native Method Libraries and provides the native libraries (C, C++) required for the execution. It enables JVM to call C/C++ libraries and to be called by C/C++ libraries which may be specific to hardware.
Native Method Libraries:
It is a collection of the Native Libraries (C, C++) which are required by the Execution Engine.
It is a collection of the Native Libraries (C, C++) which are required by the Execution Engine.
Java Garbage Collection
Garbage Collection
is a process of identifying and deleting the objects from Heap memory which are
not in use. GC frees the space after removing unreferenced objects.
The event in which Garbage
Collectors are doing their job is called “Stop the world” event
which means all of your application threads are put on hold until the garbage
is collected.
Ways for requesting JVM to run
Garbage Collector
·
Once
we made object eligible for garbage collection, it may not destroy immediately
by garbage collector. Whenever JVM runs Garbage Collector program, then only
object will be destroyed. But when JVM runs Garbage Collector, we cannot
expect.
·
We
can also request JVM to run Garbage Collector. There are two ways to do it :
1. Using System.gc() method : System class contain static
method gc() for requesting JVM to run Garbage Collector.
2. Using Runtime.getRuntime().gc() method : Runtime class allows
the application to interface with the JVM in which the application is running.
Hence by using its gc() method, we can request JVM to run Garbage Collector.
// Java
program to demonstrate requesting // JVM to
run Garbage Collector public
class Test { public
static void main(String[] args) throws InterruptedException {
Test
t1 = new Test(); Test
t2 = new Test(); //
Nullifying the reference variable t1
= null; //
requesting JVM for running Garbage Collector System.gc();
//
Nullifying the reference variable t2
= null; //
requesting JVM for running Garbage Collector Runtime.getRuntime().gc();
}
@Override //
finalize method is called on object once //
before garbage collecting it protected
void finalize() throws Throwable {
System.out.println("Garbage
collector called"); System.out.println("Object
garbage collected : " + this); }
} |
Output
Garbage collector called
Object garbage collected : Test@64d08g76
Garbage collector called
Object garbage collected : Test@638479c5
Just
before destroying an object, Garbage Collector calls finalize() method on the object to perform cleanup
activities. Once finalize() method completes,
Garbage Collector destroys that object.
The basic process of Hotspot
JVM Garbage collector completes in two phases:
Phase 1. Marking
This phase is called
marking phase in which GC identifies which objects are in use and which are not. All objects are scanned in the
marking phase to make this determination.
Phase 2. Deletion
In Deletion phase,
the marked object is deleted and the memory is released. Deletion of the
unreferenced objects can be done in two ways:
- Normal Deletion: In this
phase, all unused objects will be removed and memory allocator has
pointers to free space where a new object can be allocated.
Deletion and Compaction: As you see
in normal deletion there are free blocks between referenced objects. To
further improve performance, in addition to deleting unreferenced objects,
remaining referenced object will be compact.
Why Heap divided into
Generations
It is a cumbersome process to
scan all of the objects from a whole heap and further mark and compact
them. The list of the object grows gradually which leads to
longer garbage collection time as more and more objects are allocated
with time.
In General Applications most of
the objects are short-lived. Fewer and fewer objects remain allocated over
time.
That’s why to enhance the
performance of the JVM, Heap is broken up into smaller parts called generations and
JVM performs GC in these generations when the memory is about to fill up.
Generational Process of Garbage
Collection
Now, when you know why heap is
divided into generations, it’s time to look into how these generations would
interact.
- New objects are allocated in Eden Space of Young Generation. Both
Survivor Spaces are empty in starting.
- A minor garbage collection will trigger once the Eden space
fills up.
- Referenced objects are moved to the S0 survivor space and
Eden Space will be cleared and all unreferenced objects will be deleted.
- It will happen again to Eden space when next time GC will be
triggered. However, in this case, all referenced objects are moved to S1
survivor space. In addition, objects from the last minor GC on the S0
survivor space have their age incremented and get moved to S1. Now both
Eden and S0 will be cleared, and this process will repeat every time when
GC is triggered. On every GC triggered, survivor spaces will be switched
and object’s age will be incremented.
- Once the objects reach a certain age threshold, they are promoted
from young generation to old generation. So, this pretty much describes
how objects promotion takes place.
- The major GC will be triggered once the old generation
completely fills up.
Available Garbage collectors in
Hotspot JVM
- Serial Garbage Collector: Serial GC designed for the
single-threaded environments. It uses just a single thread to collect
garbage. It is best suited
for simple command-line programs. Though it can be used on multiprocessors
for applications with small data sets.
- Parallel Garbage Collector: Unlike
Serial GC it uses multiple threads for garbage collection. It is a default
collector of JVM and it is also called the Throughput garbage collector.
- CMS Garbage Collector: CMS uses
multiple threads at the same time to scan the heap memory and mark in the
available for eviction and then sweep the marked instances.
- G1 Garbage Collector: G1 Garbage collector is also
called the Garbage First. It is available since Java 7 and its
long-term goal is to replace the CMS collector. The G1 collector is a
parallel, concurrent, and incrementally compacting low-pause garbage
collector.
Common Heap Related
Switches
There are many different command line switches that can be used
with Java
Switch
|
Description
|
-Xms |
Sets the initial heap size for when the JVM starts.
|
-Xmx |
Sets the maximum heap size.
|
-Xmn |
Sets the size of the Young Generation.
|
-XX:PermSize
|
Sets the starting size of the Permanent Generation.
|
-XX:MaxPermSize
|
Sets the maximum size of the Permanent Generation
|
The Serial GC
The serial
collector is the default for client style machines in Java SE 5 and 6. With the
serial collector, both minor and major garbage collections are done serially
(using a single virtual CPU). In addition, it uses a mark-compact collection
method. This method moves older memory to the beginning of the heap so that new
memory allocations are made into a single continuous chunk of memory at the end
of the heap. This compacting of memory makes it faster to allocate new chunks
of memory to the heap.
Usage Cases
The Serial GC is the garbage collector of choice for most
applications that do not have low pause time requirements and run on
client-style machines. It takes advantage of only a single virtual processor
for garbage collection work (therefore, its name). Still, on today's hardware,
the Serial GC can efficiently manage a lot of non-trivial applications with a
few hundred MBs of Java heap, with relatively short worst-case pauses (around a
couple of seconds for full garbage collections).
Another popular use for the Serial GC is in environments where a
high number of JVMs are run on the same machine (in some cases, more JVMs than
available processors!). In such environments when a JVM does a garbage
collection it is better to use only one processor to minimize the interference
on the remaining JVMs, even if the garbage collection might last longer. And
the Serial GC fits this trade-off nicely.
To enable the Serial Collector use:
-XX:+UseSerialGC
The Parallel GC
The
parallel garbage collector uses multiple threads to perform the young generation garbage collection. By
default, on a host with N CPUs, the parallel garbage collector uses N garbage
collector threads in the collection. The number of garbage collector threads
can be controlled with command-line options:
-XX:ParallelGCThreads=<desired
number>
On a host with a single CPU the default garbage collector is used
even if the parallel garbage collector has been requested. On a host with two
CPUs the parallel garbage collector generally performs as well as the default
garbage collector and a reduction in the young generationgarbage collector
pause times can be expected on hosts with more than two CPUs. The Parallel GC
comes in two flavors.
Usage Cases
The Parallel collector is also called a throughput collector.
Since it can use multilple CPUs to speed up application throughput. This
collector should be used when a lot of work need to be done and long pauses are
acceptable. For example, batch processing like printing reports or bills or
performing a large number of database queries.
-XX:+UseParallelGC
With this command line option, you get a multi-thread young
generation collector with a single-threaded old generation collector. The
option also does single-threaded compaction of old generation.
-XX:+UseParallelOldGC
With the
-XX:+UseParallelOldGC
option, the GC is both a
multithreaded young generation collector and multithreaded old generation
collector. It is also a multithreaded compacting collector. HotSpot does
compaction only in the old generation. Young
generation in HotSpot is considered a copy collector; therefore, there is no
need for compaction.
Compacting describes the act of moving objects in a way that there
are no holes between objects. After a garbage collection sweep, there may be
holes left between live objects. Compacting moves objects so that there are no
remaining holes. It is possible that a garbage collector be a non-compacting
collector. Therefore, the difference between a parallel collector and a
parallel compacting collector could be the latter compacts the space after a
garbage collection sweep. The former would not.
The Concurrent Mark Sweep (CMS) Collector
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 or compact the live objects. A garbage collection is
done without moving the live objects. If fragmentation becomes a problem,
allocate a larger heap.
Note: CMS collector on young generation uses the same algorithm as
that of the parallel collector.
Usage Cases
The CMS collector should be used for applications that require low
pause times and can share resources with the garbage collector. Examples
include desktop UI application that respond to events, a webserver responding
to a request or a database responding to queries.
To enable the CMS Collector use:
and to set the number of threads use:
-XX:+UseConcMarkSweepGC
and to set the number of threads use:
-XX:ParallelCMSThreads=<n>
The G1 Garbage Collector
The Garbage
First or G1 garbage collector is available in Java 7 and is designed to be the long-term
replacement for the CMS collector. The G1 collector is a parallel, concurrent,
and incrementally compacting low-pause garbage collector that has quite a
different layout from the other garbage collectors.
To enable the G1 Collector use:
-XX:+UseG1GC
Here is the result for one
sample application with different Garbage collector
Points to Remember for tuning the Generations to
optimize the performance:
- To
explicitly enable the particular GC we can use given (-XX:+UseSerialGC, -XX:+UseSerialGC, -XX:+UseParallelGC, -XX:+UseG1GC) VM
options.
- Mainly,
two components of JVM are focused on, when tuning performance The Heap and
the Garbage Collector.
- Young
Generation is the first place to optimize the performance, to define the
size of YG we can use -XX:NewSize and -XX:MaxNewSize VM
options.
- -Xmx/2 (-Xmx to set
the maximum heap size) is an upper bound for -XX:MaxNewSize. This is
for stability reason. It is not allowed to choose a young generation’s
size larger than the old generation.
- It
is also possible to specify the young generation size in relation to the
size of the old generation using -XX:NewRation. For
example, if we set -XX: NewRatio=3, it means
the old generation will be 3 times larger then YG.
Garbage-First Garbage Collector
The Garbage-First (G1) garbage
collector is targeted for multiprocessor machines with a large amount of
memory. It attempts to meet garbage collection pause-time goals with high
probability while achieving high throughput with little need for configuration.
G1 aims to provide the best balance between latency and throughput using
current target applications and environments whose features include:
- Heap sizes up to ten of GBs or larger, with more than 50% of the
Java heap occupied with live data.
- Rates of object allocation and promotion that can vary
significantly over time.
- A significant amount of fragmentation in the heap.
- Predictable pause-time target goals that aren’t longer than a few
hundred milliseconds, avoiding long garbage collection pauses.
G1 replaces the Concurrent Mark-Sweep
(CMS) collector. It is also the default collector.
The G1 collector achieves high performance
and tries to meet pause-time goals in several ways described in the following
sections.
Enabling G1
The Garbage-First garbage collector
is the default collector, so typically you don't have to perform any additional
actions. You can explicitly enable it by providing
-XX:+UseG1GC
on the command line.
Basic Concepts
G1 is a generational, incremental,
parallel, mostly concurrent, stop-the-world, and evacuating garbage collector
which monitors pause-time goals in each of the stop-the-world pauses. Similar
to other collectors, G1 splits the heap
into (virtual) young and old generations. Space-reclamation efforts concentrate
on the young generation where it is most efficient to do so, with occasional
space-reclamation in the old generation
Some operations are always performed in stop-the-world pauses to
improve throughput. Other operations that would take
more time with the application stopped such as whole-heap operations like global marking are performed in parallel and
concurrently with the application. To keep stop-the-world pauses short for
space-reclamation, G1 performs
space-reclamation incrementally in steps and in parallel. G1 achieves
predictability by tracking information about previous application behavior and
garbage collection pauses to build a model of the associated costs. It uses
this information to size the work done in the pauses. For example, G1 reclaims space in the most efficient
areas first (that is the areas that are mostly filled with garbage, therefore
the name).
G1 reclaims space mostly by using evacuation: live objects found
within selected memory areas to collect are copied into new memory areas, compacting them in the process. After an evacuation has been
completed, the space previously occupied by live objects is reused for
allocation by the application.
The Garbage-First collector is not a
real-time collector. It tries to meet set pause-time targets with high
probability over a longer time, but not always with absolute certainty for a
given pause.
Heap Layout
G1 partitions the heap into a set of equally sized heap regions, each a contiguous range of virtual memory as shown in below Figure.
A region is the unit of memory allocation and memory reclamation. At any given
time, each of these regions can be empty
(light gray), or assigned to a particular generation, young or old. As
requests for memory comes in, the memory manager hands out free regions. The
memory manager assigns them to a generation and then returns them to the
application as free space into which it can allocate itself.
G1 Garbage Collector Heap Layout
The young generation contains eden regions (red) and survivor regions (red with "S"). These regions
provide the same function as the respective contiguous spaces in other
collectors, with the difference that in G1 these regions are typically laid out
in a noncontiguous pattern in memory. Old
regions (light blue) make up the old generation. Old generation regions may
be humongous (light blue with
"H") for objects that span multiple regions.
An application always allocates into
a young generation, that is, eden regions, with the exception of humongous,
objects that are directly allocated as belonging to the old generation.
G1 garbage collection pauses can
reclaim space in the young generation as a whole, and any additional set of old
generation regions at any collection pause. During the pause G1 copies objects
from this collection set to one or
more different regions in the heap. The destination region for an object
depends on the source region of that object: the entire young generation is
copied into either survivor or old regions, and objects from old regions to
other, different old regions using aging.
Garbage
Collection Cycle
On a high level, the G1 collector alternates between two phases.
The young-only phase contains garbage collections that fill up the currently
available memory with objects in the old generation gradually. The
space-reclamation phase is where G1 reclaims space in the old generation
incrementally, in addition to handling the young generation. Then the cycle
restarts with a young-only phase.
Below Figure gives an overview about
this cycle with an example of the sequence of garbage collection pauses that
could occur:
Garbage
Collection Cycle Overview
The following list describes the phases, their pauses and the transition between the phases of the G1 garbage collection cycle in detail:
1. Young-only phase: This phase starts with a few young-only
collections that promote objects into the old generation. The transition
between the young-only phase and the space-reclamation phase starts when the
old generation occupancy reaches a certain threshold, the Initiating Heap
Occupancy threshold. At this time, G1 schedules an Initial Mark young-only
collection instead of a regular young-only collection.
·
Initial Mark: This type of collection
starts the marking process in addition to performing a regular young-only
collection. Concurrent marking determines all currently reachable (live)
objects in the old generation regions to be kept for the following
space-reclamation phase. While marking hasn’t completely finished, regular
young collections may occur. Marking finishes with two special stop-the-world
pauses: Remark and Cleanup.
·
Remark: This pause finalizes the
marking itself, and performs global reference processing and class unloading.
Between Remark and Cleanup G1 calculates a summary of the liveness information
concurrently, which will be finalized and used in the Cleanup pause to update
internal data structures.
·
Cleanup: This pause also reclaims
completely empty regions, and determines whether a space-reclamation phase will
actually follow. If a space-reclamation phase follows, the young-only phase
completes with a single young-only collection.
2. Space-reclamation phase: This phase consists of multiple mixed
collections that in addition to young generation regions, also evacuate live
objects of sets of old generation regions. The space-reclamation phase ends
when G1 determines that evacuating more old generation regions wouldn't yield
enough free space worth the effort.
After space-reclamation, the
collection cycle restarts with another young-only phase. As backup, if the
application runs out of memory while gathering liveness information, G1
performs an in-place stop-the-world full heap compaction (Full GC) like other
collectors.
Garbage-First Internals
Determining Initiating Heap
Occupancy
The Initiating Heap Occupancy Percent (IHOP) is the
threshold at which an Initial Mark collection is triggered and it is defined as
a percentage of the old generation size.
G1 by default
automatically determines an optimal IHOP by observing how long marking takes
and how much memory is typically allocated in the old generation during marking
cycles. This feature is called Adaptive IHOP.
If this feature is active, then the option
-XX:InitiatingHeapOccupancyPercent
determines the initial value as a percentage of the
size of the current old generation as long as there aren't enough observations
to make a good prediction of the Initiating Heap Occupancy threshold. Turn off
this behavior of G1 using the option-XX:-G1UseAdaptiveIHOP
.
In this case, the value of -XX:InitiatingHeapOccupancyPercent
always determines this threshold.
Internally, Adaptive
IHOP tries to set the Initiating Heap Occupancy so that the first mixed garbage
collection of the space-reclamation phase starts when the old generation
occupancy is at a current maximum old generation size minus the value of
-XX:G1HeapReservePercent
as the extra buffer.
Marking
G1 marking uses an
algorithm called Snapshot-At-The-Beginning (SATB) .
It takes a virtual snapshot of the heap at the time of the Initial Mark pause,
when all objects that were live at the start of marking are considered live for
the remainder of marking. This means that objects that become dead
(unreachable) during marking are still considered live for the purpose of
space-reclamation (with some exceptions). This may cause some additional memory
wrongly retained compared to other collectors. However, SATB potentially
provides better latency during the Remark pause. The too conservatively
considered live objects during that marking will be reclaimed during the next
marking.
Behavior in Very Tight Heap
Situations
When the application
keeps alive so much memory so that an evacuation can't find enough space to
copy to, an evacuation failure occurs. Evacuation failure means that G1 tries
to complete the current garbage collection by keeping any objects that have
already been moved in their new location, and not copying any not yet moved
objects, only adjusting references between the object. Evacuation failure may
incur some additional overhead, but generally should be as fast as other young
collections. After this garbage collection with the evacuation failure, G1 will
resume the application as normal without any other measures. G1 assumes that
the evacuation failure occurred close to the end of the garbage collection;
that is, most objects were already moved and there is enough space left to
continue running the application until marking completes and space-reclamation
starts.
If this assumption
doesn’t hold, then G1 will eventually schedule a Full GC. This type of
collection performs in-place compaction of the entire heap. This might be very
slow.
Humongous
Objects
Humongous objects are objects larger or equal the size of
half a region. The current region size is determined ergonomically, unless set
using the
-XX:G1HeapRegionSize
option.
These
humongous objects are sometimes treated in special ways:
- Every
humongous object gets allocated as a sequence of contiguous regions in the
old generation. The start of the object itself is always located at the
start of the first region in that sequence. Any leftover space in the last
region of the sequence will be lost for allocation until the entire object
is reclaimed.
- Generally,
humongous objects can be reclaimed only at the end of marking during the
Cleanup pause, or during Full GC if they became unreachable. There is,
however, a special provision for humongous objects for arrays of primitive
types for example,
bool
, all kinds of integers, and floating point values. G1 opportunistically tries to reclaim humongous objects if they are not referenced by many objects at any kind of garbage collection pause. This behavior is enabled by default but you can disable it with the option-XX:G1EagerReclaimHumongousObjects
. - Allocations
of humongous objects may cause garbage collection pauses to occur
prematurely. G1 checks the Initiating Heap Occupancy threshold at every
humongous object allocation and may force an initial mark young collection
immediately, if current occupancy exceeds that threshold.
- The
humongous objects never move, not even during a Full GC. This can cause
premature slow Full GCs or unexpected out-of-memory conditions with lots
of free space left due to fragmentation of the region space.
Young-Only Phase Generation
Sizing
During the young-only
phase, the set of regions to collect (collection set), consists only of young
generation regions. G1 always sizes the young generation at the end of a
young-only collection. This way, G1 can meet the pause time goals that were set
using
-XX:MaxGCPauseTimeMillis
and -XX:PauseTimeIntervalMillis
based
on long-term observations of actual pause time. It takes into account how long
it took young generations of similar size to evacuate. This includes
information like how many objects had to be copied during collection, and how
interconnected these objects had been.
If not otherwise
constrained, then G1 adaptively sizes the young generation size between the
values that
-XX:G1NewSizePercent
and -XX:G1MaxNewSizePercent
determine
to meet pause-time.
Space-Reclamation Phase
Generation Sizing
During the
space-reclamation phase, G1 tries to maximize the amount of space that's
reclaimed in the old generation in a single garbage collection pause. The size
of the young generation is set to minimum allowed, typically as determined
by
-XX:G1NewSizePercent
, and any old generation regions to reclaim space are
added until G1 determines that adding further regions will exceed the pause
time goal. In a particular garbage collection pause, G1 adds old generation
regions in order of their reclamation efficiency, highest first, and the
remaining available time to get the final collection set.
The number of old
generation regions to take per garbage collection is bounded at the lower end
by the number of potential candidate old generation regions (collection set candidate regions) to collect,
divided by the length of the space-reclamation phase as determined by
-XX:G1MixedGCCountTarget
. The collection set candidate regions are all old
generation regions that have an occupancy that's lower than -XX:G1MixedGCLiveThresholdPercent
at the start of the phase.
The phase ends when the
remaining amount of space that can be reclaimed in the collection set candidate
regions is less than the percentage set by
-XX:G1HeapWastePercent
.
Ergonomic Defaults for G1 GC
This topic provides an
overview of the most important defaults specific to G1 and their default
values. They give a rough overview of expected behavior and resource usage
using G1 without any additional options.
Ergonomic
Defaults G1 GC
Option and default values |
Description |
-XX:MaxGCPauseMillis=200 |
The goal for the maximum pause time. |
-XX:GCPauseTimeInterval =<ergo> |
The goal for the maximum pause time interval.
By default G1 doesn’t set any goal, allowing G1 to perform garbage
collections back-to-back in extreme cases. |
-XX:ParallelGCThreads =<ergo> |
The maximum number of threads used for
parallel work during garbage collection pauses. This is derived from the
number of available threads of the computer that the VM runs on in the
following way: if the number of CPU threads available to the process is fewer
than or equal to 8, use that. Otherwise add five eighths of the threads
greater than to the final number of threads. |
-XX:ConcGCThreads =<ergo> |
The maximum number of threads used for
concurrent work. By default, this value is -XX:ParallelGCThreads divided by 4. |
-XX:+G1UseAdaptiveIHOP -XX:InitiatingHeapOccupancyPercent=45 |
Defaults for controlling the initiating heap occupancy
indicate that adaptive determination of that value is turned on, and that for
the first few collection cycles G1 will use an occupancy of 45% of the old
generation as mark start threshold. |
-XX:G1HeapRegionSize= <ergo> |
The set of the heap region size based on
initial and maximum heap size. So that heap contains roughly 2048 heap
regions. The size of a heap region can vary from 1 to 32 MB, and must be a
power of 2. |
-XX:G1NewSizePercent=5 -XX:G1MaxNewSizePercent=60 |
The size of the young generation in
total, which varies between these two values as percentages of the current
Java heap in use.
|
-XX:G1HeapWastePercent=5 |
The allowed unreclaimed space in the
collection set candidates as a percentage. G1 stops the space-reclamation
phase if the free space in the collection set candidates is lower than that.
|
-XX:G1MixedGCCountTarget=8 |
The expected length of the
space-reclamation phase in a number of collections.
|
-XX:G1MixedGCLiveThresholdPercent=85 |
Old generation regions with higher
live object occupancy than this percentage aren't collected in this
space-reclamation phase.
|
Comparison to Other Collectors
This is a summary of
the main differences between G1 and the other collectors:
- Parallel
GC can compact and reclaim space in the old generation only as a whole. G1
incrementally distributes this work across multiple much shorter
collections. This substantially shortens pause time at the potential
expense of throughput.
- Similar
to the CMS, G1 concurrently performs part of the old generation
space-reclamation concurrently. However, CMS can't defragment the old
generation heap, eventually running into long Full GC's.
- G1
may exhibit higher overhead than other collectors, affecting
throughput due to its concurrent nature.
Due to how it works, G1
has some unique mechanisms to improve garbage collection efficiency:
- G1
can reclaim some completely empty, large areas of the old generation
during any collection. This could avoid many otherwise unnecessary garbage
collections, freeing a significant amount of space without much effort.
- G1
can optionally try to deduplicate duplicate strings on the Java heap
concurrently.
Reclaiming empty, large
objects from the old generation is always enabled. You can disable this feature
with the option
-XX:-G1EagerReclaimHumongousObjects
. String deduplication is disabled by default. You can
enable it using the option -XX:+G1EnableStringDeduplication
.
References:
No comments:
Post a Comment