what's the difference between ParallelGC and ParallelOldGC? - java

I have some questions about the GC Algorithm:
First when we use the parameters such UseSerialGC, UseParallelGC, UseParallelOldGC and so on, we specify a GC Algorithm. Each of them all can do GC in all generation, is it right?
For example, if I use java -XX:+UseSerialGC, all generation will use serial GC as the GC Algorithm.
Second can I use ParallelGC in Old Gneneration and use SerialGC in young generation?
The last as the title what's the difference between ParallelGC and ParallelOldGC?

Take a look at the HotSpot VM Options:
-XX:+UseParallelGC = Use parallel garbage collection for scavenges. (Introduced in 1.4.1).
-XX:+UseParallelOldGC = Use parallel garbage collection for the full collections. Enabling this option automatically sets -XX:+UseParallelGC. (Introduced in 5.0 update 6.)
where Scavenges = Young generation GC.

Well, after lots of search and research what I have come to understand is as below,
-XX:+UseParallelGC - This enables GC to use multiple threads in Young generation but for old/tenured generation still Serial Mark and Compact algorithm is used.
-XX:+UseParallelOldGC - This enables GC to use Parallel Mark and Compact algorithm in old/tenured generation.
Let's understand -
The algorithm and the memory arrangement, such as mark and copy, swap spaces, that works in Young generation does not work for Old generation for many reasons
Low mortality - In the Old Generation, the "mortality rate" is significantly lower than the same in the Young Generation. In a Typical Java application most objects die quickly and few live longer. As the objects which survive in young generation and promoted to old generation, it is observed that these objects tend to live a longer life. Which leads to very less mortality rate in old generation compared to young generation.
Significantly size - The Old Generation is significantly larger than the Young Generation. Because the Young Generation quickly clears up, relatively little space is available for the many short-lived objects (small Young Generation). In the Old Generation, objects accumulate over time. Therefore, there must be much more space in an old generation than in the Young Generation (big old generation)
Little allocation - In the Old Generation less allocation happens than in the Young Generation. This is because in the Old Generation objects arise only when the Garbage Collector promotes surviving objects from the Young to the Old Generation. In the Young Generation, on the other hand, all the objects that the application generates with new, i.e the majority of the allocations, occur in the Young Generation.
Taking these differences into account, an algorithm has been chosen for the Young Generation that will finish garbage collection as soon as possible, because it has to be called often because of the high mortality rate [point (1)]. In addition, the algorithm must ensure that the most efficient possible memory allocation [point (3)] is then possible because much is allocated in the Young Generation. The mark-and-copy algorithm on the Young Generation has these properties.
On the other hand, this algorithm does not make sense on the Old Generation. The situation is different: the garbage collector has to take care of many objects in the Old Generation [point (2)] and most of them are still alive; only a small part has become unreachable and can be released [point (1)]. If the garbage collector were to copy all the surviving objects on each garbage collection, just as it does with mark-and-copy, then it would spend a lot of time copying it without gaining much.
Therefore, the mark-and-sweep algorithm is made on the old generation, where nothing is copied, but simply the unreachable objects are released. Since this algorithm leads to the fragmentation of the heap, one has additionally considered a variation of the mark-and-sweep algorithm, in which, following the sweep phase, a compaction is made, by which the fragmentation is reduced. This algorithm is called a mark-and-compact algorithm.
A mark and compact algorithm can be time consuming as it needs to traverse the object graph in following for stages.
Marking.
Calculation of new locations.
Reference adjustments.
Moving
In the Calculation of new location phase, when ever it gets a free space, tries to find an object which can move to this space(defragmentation). Stores the the pair for use in later phases. This causes the algorithm consume more time.
Though mark and compare solves some issues specific to tenured generation, it has got some serious issue as this is an STW(Stop the world) event, and consumes much time, can seriously impact the application.
Alternative algorithms for the old generation
In order to reduce the break times, alternatives to the serial mark-and-compact algorithm have been considered:
A parallel mark-and-compact algorithm that still latches all application threads, but then handles labeling and subsequent compaction with multiple garbage collector threads. While this is still a stop-the-world approach, the resulting pause is shorter on a multi-core or multi-processor machine than the serial mark-and-compact algorithm. This parallel algorithm on the Old Generation (called "ParallelOld") has been available since Java 5 Update 6 and is selected with the option -XX: + UseParallelOldGC.
A competing mark-and-sweep algorithm that at least partially rivals the application without stopping its threads, and occasionally needs short stop-the-world phases. This concurrent mark-and-sweep algorithm (called "CMS") has been around since Java 1.4.1; it is switched on with the option -XX:+UseConcMarkSweepGC. Importantly, this is just a mark-and-sweep algorithm; Compaction does not take place, leading to the already discussed problem of fragmentation.
So in a nutshell -XX: + UseParallelOldGC is used as an indication to use multiple threads while doing major collection using Mark and Compact algorithm. If this is used instead, minor or young collection are parallel, but major collections are still single threaded.
I hope this answers .

Those are two gc policies applied to different regions of a Java Heap namely New and Old generations. Here's a link that helps to clarify which options imply other ones. It's helpful especially when starting out to understand what you're getting when you specify say ParallelOldGC or ParNewGC.
http://www.fasterj.com/articles/oraclecollectors1.shtml

From Oracle Java SE 8 docs:
https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/collectors.html
The parallel collector (also known as the throughput collector) performs minor collections in parallel, which can significantly reduce garbage collection overhead. It is intended for applications with medium-sized to large-sized data sets that are run on multiprocessor or multithreaded hardware. The parallel collector is selected by default on certain hardware and operating system configurations, or can be explicitly enabled with the option -XX:+UseParallelGC.
Parallel compaction is a feature that enables the parallel collector to perform major collections in parallel. Without parallel compaction, major collections are performed using a single thread, which can significantly limit scalability. Parallel compaction is enabled by default if the option -XX:+UseParallelGC has been specified. The option to turn it off is -XX:-UseParallelOldGC.
So if you specify -XX:+UseParallelGC, By default major collection will also be done using multiple threads. The reverse is also true i.e. if you specify -XX:+UseParallelOldGC, minor collections will also be done using multiple threads.

Related

Does Java Garbage Collect always has to "Stop-the-World"?

I am trying to understand Java's garbage collection more deeply.
In HotSpot JVM generational collection, in the heap, there are three areas (Young generation, Old generation and permanent generation). Also, there are two kinds of algorithms:
1) Mark Sweep Compact.
2) Concurrent Mark and Sweep.
Is that true whether GC needs "Stop-the-world" depends on the algorithm it uses rather than which generation it operates on? In another word, if I use 1) as GC algorithm on all three areas, STW will always happen ?
Also, I understand the difference is the second GC algorithm doesn't require Compaction which will result in fragmentation eventually. So the second question comes to why the compaction needs a STW pause?
Key reason why compaction leads to STW pause is as follows, JVM needs to move object and update references to it. now if you move object before updating the references and application that is running access it from old reference than there is trouble. if you update reference first and than try to move object the updated reference is wrong till object is moved and any access while object has not moved will cause issue.
For both CMS and Parallel collecter the young generation collection algorithm is similar and it is stop the world ie application is stopped when collection is happening
Stuff JVM is doing is, marking all objects reachable from root set, moving the objects from Eden to survivor space and moving objects that have survived collections beyond tenuring threshold to the old generation. Of course JVM has to update all the references to the objects that have moved.
For old generation parallel collector is doing all marking, compaction and reference updates in a single stop the world(STW) phase, this leads to pauses in seconds for heaps in GBs. This was painful for the applications that have strict response time requirements. Till date Paralle collector is still the best collectors(among Oracle Java) for throughput or batch processing. In fact we have seen for same scenario even if time spent in pauses is more in parallel collector than CMS still we get a higher throughput, this I think has to do with better spatial locality due to compaction.
CMS solved the problem of high pauses in major collection by doing the Marking concurrently. There are 2 STW parts, Initial marking (getting the references from root set) and Remark Pause (a small STW pause at the end of marking to deal with changes in the object graph while marking and application was working concurrently). Both these pauses are in range of 100 -200 milliseconds for few GB of heap sizes and reasonable number of application threads(remember more active threads more roots)
G1GC is planned to be a replacement of CMS and accept goals for pauses. takes care of fragmentation by incrementally compacting the heap.Though the work is incremental so you can get smaller pauses but that may come at the cost of more frequent pauses
None of the above can compact heap(CMS does not compact at all) while application is running. AZUL GPGC garbage collection can even compact without stopping the application and also handle reference update. So if you want to go deep into how GCs work it will be worth reading the algorithm for GPGC. AZUL markets it as a pause-less collector.
All freely available GCs in openjdk have some stop the world events. And not just the GCs, other things such as deoptimizations can trigger safepoints too.
But not all pauses are equal. CMS and G1 do not need to scale their pause times with the live data set in the old generation because they only scan a subset of the objects during the pauses and do a major fraction of their work concurrently, unlike the Serial and Throughput collectors.
ZGC (available since OpenJDK11) and Shenandoah (since 12) are collectors that further decouple pause times from the live data set size and scale their pauses with only the root set size instead.
Additionally other GC implementations exist which avoid global pauses - they may still experience per-thread pauses - or make the pause durations O(1), i.e. independent of live data set size. A commonly cited example is azul's C4 collector.
So the second question comes to why the compaction needs a STW pause?
Compacting means moving objects. Moving objects means pointers need to be updated. This is very difficult or costly to achieve safely when applications threads are still running.
Concurrent algorithms generally pay some cost in throughput and complexity in exchange for their lower pause times. Not doing compactation makes CMS relatively(!) simple for a concurrent collector.
Here is a link that gives some good information about the different collectors in java 8: https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/collectors.html#sthref27
All strategies will stop-the-world. But, your performance requirements can drive you to choose differing GC strategies to improve performance or response times.
Stop-the-world will occur no matter which GC algorithm you choose. Stop-the-world means that the JVM is stopping the application from running to execute a GC. When stop-the-world occurs, every thread except for the threads needed for the GC will stop their tasks.

Why gc on old generation takes longer than gc on young generation

While performing GC, the JVM go over the live objects, and sweep unmarked objects.
According to:
How to Tune Java Garbage Collection
"The execution time of Full GC is relatively longer than that of Minor GC"
Will this always be the case ?
If we have ~100 objects in the Old Generation space, and the average number of live objects (created and sweep objected) in the eden space is more than 100, it that still true ?
In addition , suppose we perform compact phase , then a rule of thumb says for better performance copy a small number of large size objects than copy large number of small size objects.
So what am I missing here ?
"The execution time of Full GC is relatively longer than that of Minor
GC"
Yes.
When garbage collection happens memory is divided into generations, i.e. separate pools holding objects of different ages. Almost all most used configurations uses two generations, one for young objects (Young Generation) and one for old objects (Old Generation)
Different algorithms can be used to perform garbage collection in the different generations, each algorithm optimized based on commonly observed characteristics for that particular generation.
Generational garbage collection exploits the following observations, known as the weak generational hypothesis, regarding applications written in several programming languages, including the Java programming language:
Most allocated objects are not referenced (considered live) for long, that is, they die young.
Few references from older to younger objects exist.
Young generation collections occur relatively frequently and are efficient and fast because the young generation space is usually small and likely to contain a lot of objects that are no longer referenced.
Objects that survive some number of young generation collections are eventually promoted, or tenured, to the old generation.
This generation is typically larger than the young generation and its occupancy
grows more slowly. As a result, old generation collections are infrequent, but take significantly longer to complete.
The garbage collection algorithm chosen for a young generation typically puts a premium on speed, since young generation collections are frequent.
On the other hand, the old generation is typically managed by an algorithm
that is more space efficient, because the old generation takes up most of the heap and old generation algorithms have to work well with low garbage densities.
Read this white paper for a better understanding. The above content is referenced from there.

need help to understand available JVM "Garbage Collection Algorithm" and "Garbage Collector"

I was going through link Java - available garbage collection algorithms to understand available JVM garbage collection algorithm and got confused.
As per my understanding there will be some standard GC algorithm which different JVM vendors implement to create garbage collector.
Now please help me to understand whether below are algorithm or implementation of algorithm:
Serial,
Parallel,
CMS,
G1,
What I think these are types of garbage collectors which implements some specific algorithm (name of algorithms which I don't know).
Also I was going through white paper published on http://www.oracle.com/technetwork/java/javase/tech/memorymanagement-whitepaper-1-150020.pdf regarding JVM garbage collection but unable to get clear difference between garbage collection algorithm and garbage collector.
Some where document mentioned "Young Generation Garbage Collection Algorithm/ Old Generation Garbage Collection Algorithm".
Does it mean Serial Garbage Collector (type of garbage collector) uses "young generation garbage collection algorithm" as well as "old generation garbage collection algorithm" to do GC on young and old generation area respectively.
Please help me to get clear understanding of type of algorithm and type of garbage collector.
Uff let me try to explain this somehow :)
The garbage collector can have different algorithms - such as Mark&Sweep, Mark&Compact, Reference Counting, etc - (usally decided by how performant your system is and also the scope of your application).
Applications create objects on the heap.
Since most of these objects die young, the heap will be separated into two main regions:
Young generation and Old generation.
Objects will always land first in the young geneartion. There you have algorithms which will then promote some of the objects into old generation.
Because handling the objects in the old generation usally takes a lot of performance, the target is to let objects die as young as possible.
(This is explained really basic - Young genearation is also divided into Eden and Survivor Space - so I try to give a simple overview).
So the garbage collector uses different algorithms for the different geneartions (young and old).
Furthermore you don't only separate by algorithms but also by how they are executed:
Serial, Parallel,Concurrent...etc.
Serial
Means the garbage colletor is running in serial mode. Serial mode will be used if you only have on core. If you use serial, the garbage collector stops the world (stw phase) and clears the objects on the heap.
This can reduce performance of your application.
Parallel
The garbage colletor is running in a parallel mode. This mode uses the advantage of multi core systems. So the task to clean the heap is run in threads. This way the garbage collector needs less time to clear the heap. But you will still have stw-phases but they take less time.
CMS - Concurrent
This garbage colletor runs in a concurrent mode.
So in some phases of the garbage collector, the tasks run next to the application.
For example Concurrent Mark & Swepp:
Initial Mark Phase - Serial
Mark Phase - Concurrent
Remark Phase - Parallel
Sweep Phase - Concurrent
In the concurrent phases you won't have STW Phases.
G1
Is a special garbage colletor developed by SUN (or was it IBM?).
Currently all algorithms have Stop-The-World - Phases.
With G1 they tried to say how long these Phases will take.
This is a really complicated algorithm but also with this, it is not possible to say how long the stw phase will take.
What I think these are types of garbage collectors which implements some specific algorithm (name of algorithms which I don't know).
The ones you listed usually are used as names for specific GC implementations in context of Oracle HotSpot JVM, with all the implementation-specific details, tuning options etc. and other real-world oddities they entail.
Of course they are also based on abstract algorithms, which may share their names or could be described in some scientific publications glossing over details and just modelling their theoretic behavior.
The distinction is not always so clear-cut. A serial GC is the most primitive algorithm: mark-sweep, stop-the-world, single-threaded. Depending on the JVM it may or may not be compacting. If I recall correctly older android VMs didn't compact in their serial GC implementation.
So really, the nomenclature is context-specific. If you're reading a research paper about a parallel, compacting, concurrent, pauseless collector it does not refer to hotspot's throughput (parallel old gen), parallel scavenge (parallel young generation) or parnew (young generation collector cooperating with CMS for old gen) collector just because the word parallel is mentioned.
If you read, maybe a blog post, describing performance characteristics of specific GCs with actual measurements they probably refer to the hotspot implementations.
Here's a list of hotspot's collectors and their relations, subject to change due to pending JEPs

What is the normal behavior of Java GC and Java Heap Space usage?

I am unsure whether there is a generic answer for this, but I was wondering what the normal Java GC pattern and java heap space usage looks like. I am testing my Java 1.6 application using JMeter. I am collecting JMX GC logs and plotting them with JMeter JMX GC and Memory plugin extension. The GC pattern looks quite stable with most GC operations being 30-40ms, occasional 90ms. The memory consumption goes in a saw-tooth pattern. The JHS usage grows constantly upwards e.g. to 3GB and every 40 minutes the memory usage does a free-fall drop down to around 1GB. The max-min delta however grows, so the sawtooth height constantly grows. Does it do a full GC every 40mins?
Most of your descriptions in general, are how the GC works. However, none of your specific observations, especially numbers, hold for general case.
To start with, each JVM has one or several GC implementations and you could choose which one to use. Take the mostly applied one i.e. SUN JVM (I like to call it this way) and the common server GC pattern as example.
Firstly, the memory are divided into 4 regions.
A young generation which holds all of the recently created objects. When this generation is full, GC does a stop-the-world collection by stopping your program from working, execute a black-gray-white algorithm and get the obselete objects and remove them. So this is your 30-40 ms.
If an object survived a certain rounds of GC in the young gen, it would be moved into a swap generation. The swap generation holds the objects until another number of GCs - then move them to the old generation. There are 2 swap generations which does a double buffering kind of thing to facilitate the young gen to work faster. If young gen dumps stuff to swap gen and found swap gen is mostly full, a GC would happen on swap gen and potentially move the survived objects to old gen. This most likely makes your 90ms, though I am not 100% sure how swap gen works. Someone correct me if I am wrong.
All the objects survived swap gen would be moved to the old generation. The old generation would only be GC-ed until it's mostly full. In your case, every 40 min.
There is another "permanent gen" which is used to load your jar target byte code and resources.
All size of the areas can be adjusted by JVM parameters.
You can try to use VisualVM which would give you a dynamic idea of how it works.
P.S. not all JVM / GC works the same way. If you use G1 collector, or JRocket, it might happens slightly different, but the general idea holds.
Java GC work in terms of generations of objects. There are young, tenure and permament generations. It seems like in your case: every 30-40ms GC process only young generation (and transfers survived objects into tenure generation). And every 40 mins it performs full collecting (it causes stop-the-world pause). Note: it happens not by time, but by percentage of used memory.
There are several JVM options, which allows you to chose generation's sizes, type of GC (there are several algorithms for GC, in java 1.6 Serial GC is used by default, for example -XX:-UseConcMarkSweepGC), parameters of GC work.
You'd better try to find good articles about generations and different types of GC (algorithms are really different, some of them allow to avoid stop-the-world pauses at all!)
yes, most likely. Instead of guessing you can use jstat to monitor your GCs.
I suggest you use a memory profiler to ensure there is nothing simple you can do ti improve the amount of garbage you are producing.
BTW, If you increase the size of the young generation, you can reduce how much garbage makes it into the tenured space reducing the frequency of full collections. You may find you less than one full collection per day if you tune it enough.
For a more extreme case, I have tuned a trading system to less than one collection per day (minor or major)

Why does java wait so long to run the garbage collector?

I am building a Java web app, using the Play! Framework. I'm hosting it on playapps.net. I have been puzzling for a while over the provided graphs of memory consumption. Here is a sample:
The graph comes from a period of consistent but nominal activity. I did nothing to trigger the falloff in memory, so I presume this occurred because the garbage collector ran as it has almost reached its allowable memory consumption.
My questions:
Is it fair for me to assume that my application does not have a memory leak, as it appears that all the memory is correctly reclaimed by the garbage collector when it does run?
(from the title) Why is java waiting until the last possible second to run the garbage collector? I am seeing significant performance degradation as the memory consumption grows to the top fourth of the graph.
If my assertions above are correct, then how can I go about fixing this issue? The other posts I have read on SO seem opposed to calls to System.gc(), ranging from neutral ("it's only a request to run GC, so the JVM may just ignore you") to outright opposed ("code that relies on System.gc() is fundamentally broken"). Or am I off base here, and I should be looking for defects in my own code that is causing this behavior and intermittent performance loss?
UPDATE
I have opened a discussion on PlayApps.net pointing to this question and mentioning some of the points here; specifically #Affe's comment regarding the settings for a full GC being set very conservatively, and #G_H's comment about settings for the initial and max heap size.
Here's a link to the discussion, though you unfortunately need a playapps account to view it.
I will report the feedback here when I get it; thanks so much everyone for your answers, I've already learned a great deal from them!
Resolution
Playapps support, which is still great, didn't have many suggestions for me, their only thought being that if I was using the cache extensively this may be keeping objects alive longer than need be, but that isn't the case. I still learned a ton (woo hoo!), and I gave #Ryan Amos the green check as I took his suggestion of calling System.gc() every half day, which for now is working fine.
Any detailed answer is going to depend on which garbage collector you're using, but there are some things that are basically the same across all (modern, sun/oracle) GCs.
Every time you see the usage in the graph go down, that is a garbage collection. The only way heap gets freed is through garbage collection. The thing is there are two types of garbage collections, minor and full. The heap gets divided into two basic "areas." Young and tenured. (There are lots more subgroups in reality.) Anything that is taking up space in Young and is still in use when the minor GC comes along to free up some memory, is going to get 'promoted' into tenured. Once something makes the leap into tenured, it sits around indefinitely until the heap has no free space and a full garbage collection is necessary.
So one interpretation of that graph is that your young generation is fairly small (by default it can be a fairly small % of total heap on some JVMs) and you're keeping objects "alive" for comparatively very long times. (perhaps you're holding references to them in the web session?) So your objects are 'surviving' garbage collections until they get promoted into tenured space, where they stick around indefinitely until the JVM is well and good truly out of memory.
Again, that's just one common situation that fits with the data you have. Would need full details about the JVM configuration and the GC logs to really tell for sure what's going on.
Java won't run the garbage cleaner until it has to, because the garbage cleaner slows things down quite a bit and shouldn't be run that frequently. I think you would be OK to schedule a cleaning more frequently, such as every 3 hours. If an application never consumes full memory, there should be no reason to ever run the garbage cleaner, which is why Java only runs it when the memory is very high.
So basically, don't worry about what others say: do what works best. If you find performance improvements from running the garbage cleaner at 66% memory, do it.
I am noticing that the graph isn't sloping strictly upward until the drop, but has smaller local variations. Although I'm not certain, I don't think memory use would show these small drops if there was no garbage collection going on.
There are minor and major collections in Java. Minor collections occur frequently, whereas major collections are rarer and diminish performance more. Minor collections probably tend to sweep up stuff like short-lived object instances created within methods. A major collection will remove a lot more, which is what probably happened at the end of your graph.
Now, some answers that were posted while I'm typing this give good explanations regarding the differences in garbage collectors, object generations and more. But that still doesn't explain why it would take so absurdly long (nearly 24 hours) before a serious cleaning is done.
Two things of interest that can be set for a JVM at startup are the maximum allowed heap size, and the initial heap size. The maximum is a hard limit, once you reach that, further garbage collection doesn't reduce memory usage and if you need to allocate new space for objects or other data, you'll get an OutOfMemoryError. However, internally there's a soft limit as well: the current heap size. A JVM doesn't immediately gobble up the maximum amount of memory. Instead, it starts at your initial heap size and then increases the heap when it's needed. Think of it a bit as the RAM of your JVM, that can increase dynamically.
If the actual memory use of your application starts to reach the current heap size, a garbage collection will typically be instigated. This might reduce the memory use, so an increase in heap size isn't needed. But it's also possible that the application currently does need all that memory and would exceed the heap size. In that case, it is increased provided that it hasn't already reached the maximum set limit.
Now, what might be your case is that the initial heap size is set to the same value as the maximum. Suppose that would be so, then the JVM will immediately seize all that memory. It will take a very long time before the application has accumulated enough garbage to reach the heap size in memory usage. But at that moment you'll see a large collection. Starting with a small enough heap and allowing it to grow keeps the memory use limited to what's needed.
This is assuming that your graph shows heap use and not allocated heap size. If that's not the case and you are actually seeing the heap itself grow like this, something else is going on. I'll admit I'm not savvy enough regarding the internals of garbage collection and its scheduling to be absolutely certain of what's happening here, most of this is from observation of leaking applications in profilers. So if I've provided faulty info, I'll take this answer down.
As you might have noticed, this does not affect you. The garbage collection only kicks in if the JVM feels there is a need for it to run and this happens for the sake of optimization, there's no use of doing many small collections if you can make a single full collection and do a full cleanup.
The current JVM contains some really interesting algorithms and the garbage collection itself id divided into 3 different regions, you can find a lot more about this here, here's a sample:
Three types of collection algorithms
The HotSpot JVM provides three GC algorithms, each tuned for a specific type of collection within a specific generation. The copy (also known as scavenge) collection quickly cleans up short-lived objects in the new generation heap. The mark-compact algorithm employs a slower, more robust technique to collect longer-lived objects in the old generation heap. The incremental algorithm attempts to improve old generation collection by performing robust GC while minimizing pauses.
Copy/scavenge collection
Using the copy algorithm, the JVM reclaims most objects in the new generation object space (also known as eden) simply by making small scavenges -- a Java term for collecting and removing refuse. Longer-lived objects are ultimately copied, or tenured, into the old object space.
Mark-compact collection
As more objects become tenured, the old object space begins to reach maximum occupancy. The mark-compact algorithm, used to collect objects in the old object space, has different requirements than the copy collection algorithm used in the new object space.
The mark-compact algorithm first scans all objects, marking all reachable objects. It then compacts all remaining gaps of dead objects. The mark-compact algorithm occupies more time than the copy collection algorithm; however, it requires less memory and eliminates memory fragmentation.
Incremental (train) collection
The new generation copy/scavenge and the old generation mark-compact algorithms can't eliminate all JVM pauses. Such pauses are proportional to the number of live objects. To address the need for pauseless GC, the HotSpot JVM also offers incremental, or train, collection.
Incremental collection breaks up old object collection pauses into many tiny pauses even with large object areas. Instead of just a new and an old generation, this algorithm has a middle generation comprising many small spaces. There is some overhead associated with incremental collection; you might see as much as a 10-percent speed degradation.
The -Xincgc and -Xnoincgc parameters control how you use incremental collection. The next release of HotSpot JVM, version 1.4, will attempt continuous, pauseless GC that will probably be a variation of the incremental algorithm. I won't discuss incremental collection since it will soon change.
This generational garbage collector is one of the most efficient solutions we have for the problem nowadays.
I had an app that produced a graph like that and acted as you describe. I was using the CMS collector (-XX:+UseConcMarkSweepGC). Here is what was going on in my case.
I did not have enough memory configured for the application, so over time I was running into fragmentation problems in the heap. This caused GCs with greater and greater frequency, but it did not actually throw an OOME or fail out of CMS to the serial collector (which it is supposed to do in that case) because the stats it keeps only count application paused time (GC blocks the world), application concurrent time (GC runs with application threads) is ignored for those calculations. I tuned some parameters, mainly gave it a whole crap load more heap (with a very large new space), set -XX:CMSFullGCsBeforeCompaction=1, and the problem stopped occurring.
Probably you do have memory leaks that's cleared every 24 hours.

Categories

Resources