Garbage Collector etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster
Garbage Collector etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster

15 Eylül 2023 Cuma

Generational Z Garbage Collector

Giriş
Açıklaması şöyle. Yani ZGC çok büyük heap'leri destekliyor.
ZGC now supports Terabyte-size Java Heaps with permanent sub-millisecond pauses. No important caveats... it may use say 5-10% more memory or 5-10% slower allocation speed, but no more stop-the-world GC pauses and no more heap size limits. 
Açıklaması şöyle
Generational ZGC
The generational hypothesis is the observation that younger objects are much more likely to “die young” than older objects, at least in most cases. That’s why handling objects differently based on their age can be beneficial. Improving the collection of younger objects requires fewer resources and yields more memory.

Even without handling generations, ZGC is quite an improvement in GC pause times, reclaiming memory faster than concurrent threads consume them, at least if enough resources are available. However, all objects are stored regardless of their age, and all of them have to be checked when the GC runs.

With Java 21, the ZGC splits the heap into two logical generations: one for recently allocated objects and another for long-lived objects. The GC can focus on collecting younger and more promising objects more often without increasing pause time, keeping them under 1 millisecond.

The generational ZGC should give us

- Lower risks of allocation stalls
- Lower required heap overhead
- Lower GC CPU impact
All these benefits should come without a significant decrease in throughput compared to non-generational ZGC. Also, there shouldn’t be a need to configure the size of the generations, threads used, or the age limit ourselves.
Örnek
Şöyle yaparız
# Enable ZGC (defaults to non-generational)
$ java -XX:+UseZGC

# Use Generational ZGC
$ java -XX:+UseZGC -XX:+ZGenerational

# Do not use Generational ZGC
$ java -XX:+UseZGC -XX:-ZGenerational



20 Temmuz 2022 Çarşamba

Epsilon Garbage Collector - Java 11 İle Geliyor

Giriş
Açıklaması şöyle
Epsilon only allocates memory and does not release it like JVM GC. Using this new garbage collector is really helpful in a test environment as no memory clearance overhead. Therefore, it gives an accurate performance test result. There is a note that Epsilon is good only for test environments because it will lead to OOM (OutOfMemory) in production and crash the Java application.
Açıklaması şöyle
Java 11 introduced a no-operations(No-Op) garbage collector called Epsilon. This is an experimental feature. It is called a No-Op garbage collector because it will allocate memory but will never collect any garbage. We can use it for simulating Out-Of-Memory errors. The following are some of its use cases.

- Performance testing
- Memory pressure testing
- VM interface testing and
- Extremely short-lived jobs
- Last-drop latency and throughput improvements
Örnek
Şöyle yaparız
-XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC



 

2 Kasım 2021 Salı

Garbage Collector Patterns

Giriş
GC Pattern'ları grafiksel olarak bakınca daha net görülüyor. Bunlar şöyle

1. Healthy saw-tooth pattern - Sağlıklı
2. Heavy caching pattern - Kabul edilebilir

3. Acute memory leak pattern - Düzeltilmeli
4. Consecutive Full GC pattern - Belki Düzeltilebilir
5. Memory Leak Pattern - Düzeltilmeli

1. Healthy saw-tooth pattern
Bu örüntüden CG gerçekleşince, heap kullanımı tekrar eski seviyeye düşer. Testere dişleri gibidir. Şeklen şöyle
Bir diğer şekil de şöyle. Heap bitince hemen hemen tüm bellek boşaltılıyor.


2. Heavy caching pattern - Kabul edilebilir
Burada aslında testere dişleri var gibi görünse de, heap kullanımı en alt seviyeye düşmüyor. Yani uygulama çok fazla şeyi bellekte saklamaya çalışıyor. Şeklen şöyle

3. Acute memory leak pattern - Düzeltilmeli
Heap kullanımı sürekli artar. Şeklen şöyle

Bir diğer şekil de şöyle. Bu örnekte de OOM exception ile uygulama sonlanır.


4. Consecutive Full GC pattern - Belki Düzeltilebilir
Uygulamaya aniden yük binince belli bir süre boyunca ardışık olarak GC döngüsüne girer. Aslında yapacak çok bir şey yok. Yükü dağıtmak denenebilir. Şeklen şöyle

5. Memory Leak Pattern - Düzeltilmeli
Uygulamada bir olay olur ve ondan sonra sızıntı olmaya başlar. Şeklen şöyle


















18 Ocak 2021 Pazartesi

Garbage Collector Terminolojisi

Giriş
Burada Garbage Collector (GC) yazılarında çokça kullanılan bazı terminolojiyi açıklamaya çalıştım. Açıklaması şöyle. Aralarındaki en öenmli fark ne kadar CPU kullandıkları ve ne kadar süre tuttukları
GC phases can have different properties:

- a parallel phase can run on multiple GC threads
- a serial phase runs on a single thread
- a stop-the-world phase can't run concurrently with application code
- a concurrent phase can run in the background, while our application does its work
- an incremental phase can terminate before finishing all of its work and continue it later

Note that all of the above techniques have their strengths and weaknesses. For example, let's say we have a phase that can run concurrently with our application. A serial implementation of this phase requires 1% of the overall CPU performance and runs for 1000ms. In contrast, a parallel implementation utilizes 30% of CPU and completes its work in 50ms.

In this example, the parallel solution uses more CPU overall, because it may be more complex and have to synchronize the threads. For CPU heavy applications (for example, batch jobs), it's a problem since we have less computing power to do useful work.
1. Parallel Garbage Collector Nedir?
Açıklaması şöyle. GC işlemi için birden fazla thread kullanır. Ancak concurrent değildir. Yani uygulamayı durdurur.
When a garbage collector is described as parallel, it uses multiple threads to perform garbage collection.
2. Concurrent Garbage Collector Nedir?
Açıklaması şöyle. Mark aşamasında uygulama ile birlikte çalışır, yani uygulama durdurulmaz. Sweep aşamasında uygulama mecburen durdurulur.
The term concurrent means that garbage collection activity is occurring at the same time as the Java application is executing. 
3. Stop the World Nedir?
Açıklaması şöyle.  Uygulamayı durdurulur. "Stop the World" emrini az veren GC "Low Pause GC" denilir.
The term stop-the-world means that all Java application threads are stopped during a GC event. A stop-the-world garbage collector is one that stops all Java application threads when it performs a garbage collection. A GC phase or event may be described as stop-the-world, which means that during that particular GC phase or event all Java application threads are stopped.
4. Java Heap Bölümleri Nelerdir
3 kısma ayrılır. Açıklaması şöyle
The heap was divided into the following three categories:

Eden: This where the Objects born. Like in the Bible.
Survivor: If an object lives long enough, it will go into the Survivor area.
Tenured: If it getting really old it will be moved into the Tenured area.
- Eden ve Survivor aynı zamanda Young Generation olarak bilinir.  Tenured ise Old Generation olarak ta bilinir.
- Eden alanında GC daha sık çalışmalıdır.

5. GC Events Nelerdir?

5.1 Minor GC Nedir?
Eden alanı dolunca gerçekleşir. Sadece Young Generation (Eden + Young) alanlarının temizlenmesidir. Açıklaması şöyle. Bu işlem sonucunda Eden temizlenir. Eden'deki nesneler Survivor alanına taşınır. Survivor alanındaki bazı nesneler Old Generation alanına taşınır.
1. When allocating an object, it is allocated in the Eden space. This means that those regions that have been designated as “Eden” are the first place that new objects will be added.
2. After the Eden space gets full, a “Minor Garbage Collection” (Minor GC) will start. A Minor GC seeks to free up memory by removing objects from Eden and Survivor regions only. This helps to keep these regions empty and available for new objects.
3. After the Minor GC has finished, any objects that remain in the Eden space will be moved into the Survivor space.
4. Objects in the survivor space that pass the age threshold are moved to the “Old Generation” region. Any objects that haven’t met the age threshold will remain in the survivor space.
Minor GC başında şöyledir. Burada kırmızı nesneler temizlenecekler, mavi nesneler ise Survivor 1 alanına taşınacaklar

İkinci Minor GC'de ise Survivor 1'deki nesneler, Survivor 2'ye taşınacaklar.




5.2 Mixed GC Nedir?
Açıklaması şöyle
It is a Minor GC with some of the old regions are also cleared out (This event is more complicated than a Minor event...)
5.3 Major GC Nedir?
Old Generation (Tenured) alanının temizlenmesidir.

5.3 Full GC Nedir?
Young ve Old Generation alanlarının temizlenmesidir. Açıklaması şöyle
Everything is evacuated. This is typically a bad sign.
6. Nesnelerin Taşınması Yöntemleri
Nesnelerin taşınması bazı GC'lerde Young Generation ve Old Generation için ayrı ayrı seçilebiliyor. Bazılarında ise hepsi için aynı yöntem kullanılıyor.
 
6.1 Mark-sweep
Mark-sweep Nedir yazısına taşıdım. Nesne olduğu yerde bırakılır.

6.2 Mark-sweep-compact
Nesne aynı blokta yan yana olacak şekilde taşınır

6.3 Mark-copy 
Nesne başka bloğa taşınır

28 Mayıs 2020 Perşembe

Concurrent Mark Sweep Garbage Collector - Java 8 İçin Belki Kullanılabilir, Java 14 İle Kaldırıldı

Giriş
Yazı uzun, bu yüzden kısaca özetlemek gerekirse
- Young Generation için "Stop the World" emri verilir ve Paralel Mark Copy (Scavenge) kullanır. Yani nesne başka bir bloka taşınır
- Old Generation için eğer mecbur değilse "Stop the World" emri verilmez ve Mark Sweep kullanır. Yani nesne olduğu yerde bırakılır. Aynı bloktaki nesneler arasında boşluklar oluşur. 

Kullanmak
Kullanmak için şöyle yaparız
-XX:+UseConcMarkSweepGC  -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -Xms1024m       -XX:+PrintCommandLineFlags -jar foo.jar
CMS vs Paralel Collector
CMS ve Paralel Collector bence Young Generation için aynı mantıkta çalışıyor. Her ikisi de "Stop the World" emrini veriyor ve paralel olarak işi hızlıca bitirmeye çalışıyor. Ancak CMS Minor GC işlemini çok daha sık yapıyor, Ayrıca ParNew içinde Old Generation'a bir callback gönderiyor.

Esas fark Old Generation'da ortaya çıkıyor. Paralel Collector, Major GC işleri için de "Stop the World" emri verirken, CMS major GC için concurrent yani uygulama thread'leri ile birlikte çalışarak "Stop the World" emrini mümkün olduğunca az vermeye çalışıyor.

Ayrıca GC biraz daha fazla yük getiriyor. Açıklaması şöyle
Aims for low pause times but has higher overall GC overhead. It’s generally less preferred than G1 in modern Java versions.
Java 9 ve Ötesi
Java 9 ile CMS kullanmaya çalışınca yani şöyle yaparsak
XX:+UseConcMarkSweepGC
bize uyarı veriyor. Uyarı şöyle
Java HotSpot(TM) 64-Bit Server VM warning: Option UseConcMarkSweepGC was deprecated in 
version 9.0 and will likely be removed in a future release.
Bu GC Java 14 ile tamamen kaldırıldı. Açıklaması şöyle.
As of Java 9, the CMS garbage collector has been deprecated. Therefore, JVM prints a warning message if we try to use it:
...
Moreover, Java 14 completely dropped the CMS support:
Yerine Ne Kullanabiliriz ?
- Java 9 için G1 kullanılabilir
- Java 11,12 için Z kullanılabilir

Law Pause Ne Demek
Bu Garbage Collector "Low Pause" algoritmalardan bir tanesi. Stop the World emrini mümkün olduğunca az veriyor. Açıklaması şöyle.
The Concurrent Mark Sweep (CMS) collector is designed to be a lower latency collector than the parallel collectors. The key part of this design is trying to do part of the garbage collection at the same time as the application is running. This means that when the collector needs to pause the application's execution it doesn't need to pause for as long.

CMS uses the parallel stop-the-world mark-copy algorithm in the Young Generation and concurrent mark-sweep algorithm in the Old Generation.
Yani işlemci ve belleği daha fazla kullanarak, daha az Stop the World emrini veriyor. Açıklaması şöyle
It's designed for applications that prefer shorter garbage collection pauses, and that can afford to share processor resources with the garbage collector while the application is running.

Simply put, applications using this type of GC respond slower on average but do not stop responding to perform garbage collection.
Footprint
Açıklaması şöyle. Parallel Collector 'a göre daha fazla bellek harcar ancak karşılığında daha kısa duraklama (Low Pause) sağlar.
This CMS collector requires more footprint than Parallel Collector and it has more data structures to take care of. It has less throughput than the Parallel Collector but the advantage is it has smaller pauses than the Parallel Collector. This collector is the best-used collector for all the general Java applications
CMS Collector Belleği İşletim Sistemine Geri Verir
Açıklaması şöyle. Ancak bir kaç full GC işleminden sonra geri verir.
Serial and ConcMarkSweep are also shrinking garbage collectors and can scale memory usage in JVM vertically. But in comparison to G1, they require 4 Full GC cycles to release all unused resources.
2. CMS Nedir
Açıklaması şöyle
It attempts to minimize the pauses due to garbage collection by doing most of the garbage collection work concurrently with the application threads. It uses the parallel stop-the-world mark-copy algorithm in the Young Generation and the mostly concurrent mark-sweep algorithm in the Old Generation.
3. Young Generation - Mark Copy 
Young Generation çalışırken "Stop the World" emri verilir. Mark-copy olduğu için yaşamasına karar verilen nesneler başka bloğa taşınır

Young Generation için Serial veya Parallel seçenekleri ile çalıştırılabilir.

3.1. Serial Seçeneği - Kullanmayın
Serial için şöyle yaparız. UseParNewGC'nin başında eksi var. Bu yöntem deprecated olarak işaretli ve Java 9 ile de kaldırıldı. Dolayısıyla kullanmamak lazım
-XX:+UseConcMarkSweepGC  -XX:-UseParNewGC
3.2. UseParNewGC Seçeneği  - parallel copying collector
Eğer sadece UseConcMarkSweepGC belirtilirse bu seçenek etkinleştirilmiş varsayılır. Açıklaması şöyle.
UseParNewGC A parallel version of the young generation copying collector is used with the concurrent collector (i.e. if -XX:+ UseConcMarkSweepGC is used on the command line then the flag UseParNewGC is also set to true if it is not otherwise explicitly set on the command line).
Bu seçeneği illaki belirtmek istersek şöyle yaparız.
XX:+UseConcMarkSweepGC -XX:+UseParNewGC
Açıklaması şöyle. 
The parallel copying collector (Enabled using -XX:+UseParNewGC). Like the original copying collector, this is a stop-the-world collector. However this collector parallelizes the copying collection over multiple threads, which is more efficient than the original single-thread copying collector for multi-CPU machines (though not for single-CPU machines). This algorithm potentially speeds up young generation collection by a factor equal to the number of CPUs available, when compared to the original singly-threaded copying collector.
Bu yüzden GC loglarında şuna benzer bir çıktı görürüz
[GC (Allocation Failure) ...  [ParNew: ....]
Açıklaması şöyle
Parallel New (ParNew) Collector (invoked by "-XX:+UseConcMarkSweepGC" option) - The ParNew collector for Young generation uses the "Copy (also called Scavenge)" algorithm parallelly using multiple CPU processors (multiple threads) in a stop-the-world fashion.

The ParNew collector for Young (new) generation uses the same algorithm as the PS collector, except that it has an internal 'callback' that allows an old generation collector to operate on the objects it collects (really written to work with the concurrent collector), as described by Jack Shirazi in "Oracle JVM Garbage Collectors Available From JDK 1.7.0_04 And After".

The ParNew collector for Young generation can be identified in GC log messages with the "ParNew" label, as in this example: "ParNew: 1068K->63K(1152K)".

In JVM 9 and older releases, the ParNew collector for Young generation can be invoked explicitly using the "-XX:+UseParNewGC" option. But this option has been removed from JVM 10.
4. Old Generation - Concurrent Mark Sweep
Old Generation için uygulama ile eş zamanlı çalışarak "Stop the World" emrinin mümkün olduğunca az olmasına uğraşır. Mark-sweep olduğu için yaşamasına karar verilen nesneler oldukları yerde bırakılırlar. Yani başka bloğa veya yan yana olacak şekilde yer değiştirmez. Aynı bloktaki nesneler arasında boşluklar oluşur.

Bu Garbage Collector Java 9'dan itibaren kullanılmamalı. Açıklaması şöyle.  Java 9'dan itibaren G1 artık en çok tercih edilen garbage collector.
The Concurrent Mark Sweep (CMS) collector has been deprecated since Java 9...

Shenandoah Garbage Collector

Giriş
Açıklaması şöyle.
There is one more collector called Shenandoah Collector. This collector is an improvement upon G1 collector wherein it requires a little higher footprint so it takes more data structures behind the scenes but it has even lower latency than G1 collector.

Shenandoah is an ultra-low pause time garbage collector that reduces GC pause times by performing more garbage collection work concurrently with the running Java program. CMS and G1 both perform concurrent marking of live objects. Shenandoah adds concurrent compaction.

2 Mart 2020 Pazartesi

Parallel Collector - Java 8 İçin Varsayılan GC

Giriş
Açıklaması şöyle. GC çalışırken "Stop the World" emri verilir. Bir seferde mümkün olduğunca fazla GC işlemini paralel olarak yapmaya çalışır. Dolayısıyla "Low Pause" bir collector değildir.
Similar to serial GC, It uses mark-copy in the Young Generation and mark-sweep-compact in the Old Generation. Multiple concurrent threads are used for marking and copying / compacting phases. You can configure the number of threads using -XX:ParallelGCThreads=N option.
Java 8
- Java 7'den önce minor GC için - yani Young Space için - paralel thread'ler, ancak major GC için - yani Old Space için - tek thread kullanıyordu. Yani major GC maliyetliydi.

- Java 7'den itibaren tüm minor ve major GC işlemleri için paralel thread'ler kullanır. Dolayısıyla işini mümkün olduğunca hızlı bitirmeye çalışır

Şeklen şöyle. Burada Parallel GC kullanılırsa yan yana bir sürü sarı çizgi yani GC thread görülebilir.


Parallel Collector Belleği İşletim Sistemine Geri Vermez
Açıklaması şöyle.
Parallel is a high throughput GC and used by default in JDK8. At the same time, it does not suit for memory shrinking that makes it inappropriate for flexible vertical scaling.
...
As we can see, the unused RAM is not released back to OS. JVM with Parallel GC keeps it forever, even disregarding the explicit Full GC calls.
Young Generation - Mark-copy
Mark-copy olduğu için yaşamasına karar verilen nesneler başka bloğa taşınır

Old Generation - Mark-sweep-compact
Mark-sweep-compact olduğu için yaşamasına karar verilen nesneler aynı blokta yan yana olacak şekilde taşınırlar.


18 Eylül 2019 Çarşamba

Z Garbage Collector

Giriş
Java 11 ile deneysel olarak geldi, Java 15 ile tam kullanıma girdi.

Kullanım senaryosu şöyle
 Garbage Collectors | Scenarios
====================|==========================================
 * Serial           | * Small data sets (~100 MB max)
                    | * Limited resources (e.g., single core)
                    | * Low pause times
--------------------|------------------------------------------
 * Parallel         | * Peak performance in multi-core systems
                    | * High computational loads
                    | * Greater than 1sec pauses are acceptable
--------------------|------------------------------------------
 * G1               | * Response time over throughput
 * CMS              | * Large heap
                    | * Pauses less than 1sec
--------------------|------------------------------------------
 * Shenandoah       | * Minimize pause times
                    | * Predicatable latencies
--------------------|------------------------------------------
 * ZGC              | * Response time is high-priority, and/or
                    | * Very large heap
--------------------|------------------------------------------
 * Epsilon GC       | * Performance testing and troubleshooting
Z Garbage Collector
Açıklaması şöyle.
Z GC is a scalable, low-latency garbage collector. Its goal is to keep GC pause times less than 10ms. Early access of Z GC algorithm is available in Java 11 and 12. So if your application is running on Java 11 or 12, you may consider upgrading to Z GC algorithm. 
Açıklaması şöyle. Burada en önemli nokta GC Pause süresini 10 milisaniyenin altında tutmak. Bunu da concurrent çalışmasına borçlu.  Ayrıca sadece root scanning yaptığı için stop-the-world kısa sürüyor
As a concurrent garbage collector, ZGC guarantees not to exceed application latency by 10 milliseconds, even for bigger heap sizes. ...

The stop-the-world pauses are limited to root scanning in ZGC. It uses load barriers with colored pointers to perform concurrent operations when the threads are running and they are used to keep track of heap usage. Colored pointers are one of the core concepts of ZGC and it enables ZGC to find, mark, locate, and remap the objects. Compared to G1, ZGC has better ways to deal with very large object allocations which are highly performant when it comes to reclaiming memory and reallocating it and it is a single-generation GC.

ZGC divides memory into regions, also called ZPages. These ZPages can be dynamically created and destroyed and can also be dynamically sized. Unlike other GCs, the physical heap regions of ZGC can map into a bigger heap address space (which can include virtual memory) which can avoid memory fragmentation issues.
Şu işleri concurrent yapıyor
ZGC is a concurrent low latency algorithm, it does everything concurrent (marking, compaction, reference processing, relocation set selection, StringTable cleaning, JNI WeakRef cleaning, JNI GlobalRefs scanning and class unloading), except thread stack scanning. This makes the algorithm really good for low latency.
ZGC vs G1GC
Açıklaması şöyle. Yani Humongous nesnelerde ZGC daha iyi
ZGC boasts some outstanding benchmarks when dealing with large objects.
Ne Zaman Kullanılır
Açıklaması şöyle. G1 GC'ye göre daha büyük heap alanını destekliyor.
ZGC was experimental until recent versions of the JVM. It’s designed for even larger heap sizes than G1 and is also a concurrent GC. It does support smaller environments and can be used for heap size as small as 8mb all the way to 16TB maximum heap size!

One of its biggest features is that it doesn’t pause the execution of the application for more than 10ms. The cost is a reduction in throughput.

ZGC can be enabled using the -XX:+UseZGC JVM option.
Root Scanning Thread Sayısı İle İlgili
Açıklaması şöyle
One important thing to mention is that currently, pause times do not increase with the heap or live size, however, pause times do increase with the root-set size (number of java threads that your application is using).
The ZGC Phases
Açıklaması şöyle
The GC cycle of ZGC is divided into three pauses.

- In the first phase, Pause Mark Start, ZGC walks through the object graph to mark the objects live or garbage. This phase also includes the remapping of live data.
- The second phase, Pause Mark End, is where reference preprocessing is done. The class unloading and relocation set selection are also done in this phase.
- Pause Relocate Start, the last phase, is where the heavy job of compacting the heap happens.

Reference Coloring
ZGC reference için 64 bit kullanır. Ancak bunun sadece 42 bit'i bellek adresini gösterir. Geri kalan bitler referans hakkındaki bazı bilgiler içindir. Şeklen şöyle


Açıklaması şöyle
A reference represents the position of a byte in the virtual memory. However, we don't necessarily have to use all bits of a reference to do that – some bits can represent properties of the reference. That's what we call reference coloring.

With 32 bits, we can address 4 gigabytes. Since nowadays it's widespread for a computer to have more memory than this, we obviously can't use any of these 32 bits for coloring. Therefore, ZGC uses 64-bit references. It means ZGC is only available on 64-bit platforms:

ZGC references use 42 bits to represent the address itself. As a result, ZGC references can address 4 terabytes of memory space.

On top of that, we have 4 bits to store reference states:

- finalizable bit – the object is only reachable through a finalizer
- remap bit – the reference is up to date and points to the current location of the object (see relocation)
- marked0 and marked1 bits – these are used to mark reachable objects

We also called these bits metadata bits. In ZGC, precisely one of these metadata bits is 1.
Heap Nasıldır?
Heap ZPage yapısından oluşur. Açıklaması şöyle
It is a region-based collector, which means that the heap is divided into smaller regions and the compaction efforts will be focused on a subset of those regions, the ones with the most garbage.
ZPageCache
Açıklaması şöyle. ZGC belleği işletim sistemine geri verebilir.
The ZGC heap consists of a set of heap regions called ZPages. When ZPages are emptied during a GC cycle, they are returned to the ZPageCache. ZPages in this cache are organized by least recently used order. In JDK 13, the ZGC will return pages that have been identified as unused for a sufficiently long period of time to the operating system. This allows them to be reused for other processes. Uncommitting memory will never cause the heap size to shrink below the minimum size specified on the command line. If the minimum and maximum heap sizes are set to the same value, no memory will be uncommitted.
Belleği İşletim Sistemine Geri Verme Özelliği Niye lazım ?
Açıklaması şöyle.
ZGC is an experimental low-latency garbage collector, introduced in JDK 11. ZGC's original design did not allow for memory pages to be returned to the operating system when they were no longer required; when the heap shrinks and the memory is unused for an extended period of time. For environments such as containers, where resources are shared between a number of services, this can limit the scalability and efficiency of the system.
Seçenekler
Seçenekler şöyle
-XX:ZAllocationSpikeTolerance
-XX:ZCollectionInterval
-XX:ZFragmentationLimit
-XX:ZMarkStackSpaceLimit
-XX:ZProactive
-XX:ZUncommit
-XX:ZUncommitDelay
ZUncommit seçeneği - Not Returning Unused Memory to the Operating System
Açıklaması şöyle
Unlike other GC algorithms, ZGC uncommits unused memory, giving it back to the operating system. This can be necessary for applications where memory footprint can be a problem. If you want to disable this option, you can use -XX:-ZUncommit.

-XX:+UseZGC -Xmx<size> -XX:-ZUncommit
Açıklaması şöyle
ZGC is efficiently designed to manage large heap sizes. Allocating a large heap size when application doesn’t need it can result in inefficient memory usage. By default, ZGC uncommits unused memory, returning it to the operating system. This feature can be disabled using -XX:-ZUncommit. 

ZGC ensures that memory is not uncommitted to the extent that the heap size falls below the specified minimum heap size (-Xms). Consequently, if the minimum heap size is set to match the maximum heap size (-Xmx), the uncommit feature will be implicitly disabled.

To provide flexibility in managing uncommitted memory, ZGC allows you to configure an uncommit delay using the -XX:ZUncommitDelay=<seconds> option, with a default delay of 300 seconds. This delay specifies the duration for which memory should remain unused before it becomes eligible for uncommit.
-XX:ConcGCThreads=<number>
Açıklaması şöyle
Another interesting tuning option to consider is the number of concurrent garbage collection (GC) threads in ZGC, which can be configured using the -XX:ConcGCThreads=<number> flag. ZGC has built-in heuristics to automatically select the optimal number of threads based on the characteristics of your application. The default heuristic in ZGC usually works well for most scenarios. However, depending on the specific behavior and requirements of your application, you may need to adjust the number of concurrent GC threads. This parameter determines how much CPU time is allocated to the garbage collector. Allocating too many threads can result in excessive CPU usage by the GC, taking away valuable resources from your application. On the other hand, allocating too few threads may slow down the GC performance. 

Starting from JDK 17, ZGC introduced dynamic scaling of the number of concurrent GC threads. This means that ZGC can automatically adjust the number of threads based on the workload, making it less likely for you to manually tune this parameter.
-XX:+UseLargePages - Enabling Large Pages
Açıklaması şöyle
Configuring ZGC to utilize large pages can enhance throughput, reduce latency, and improve startup time. Large pages, also known as huge pages, have a size of 2MB on Linux/x86 systems. Large pages are memory pages that are larger than the standard page size. They offer benefits such as reduced memory management overhead and improved memory access efficiency. 

To enable large pages in ZGC, you need to configure the -XX:+UseLargePages option in the JVM.  
-XX:+UseTransparentHugePages - Enabling Transparent Huge Pages
Açıklaması şöyle
An alternative to using explicit large pages (as described above) is to use Transparent Huge Pages (THP). THP is a feature in the Linux kernel that automatically aggregates standard memory pages into larger, more efficient huge pages. THP aims to improve memory management by reducing the overhead associated with managing individual pages. By grouping multiple standard pages into a single huge page (typically 2MB in size), THP can potentially enhance performance.

To enable Transparent Huge Pages in the JVM, you can use the -XX:+UseTransparentHugePages option. This allows the Java application to take advantage of the large, aggregated memory pages managed by the operating system. It’s important to note that THP may introduce latency spikes in certain scenarios, which makes it less suitable for latency-sensitive applications. Before enabling THP, it is recommended to evaluate its impact on your specific workload and performance requirements.
-XX:+UseNUMA - Enabling NUMA Support
Açıklaması şöyle
ZGC has NUMA support, which means it will try its best to direct Java heap allocations to NUMA-local memory. NUMA stands for Non-Uniform Memory Access and refers to the architecture design used in multi-socket systems. In NUMA systems, memory is divided into multiple memory nodes, with each node associated with a specific processor or socket. Each processor has faster access to its own local memory node compared to accessing remote memory nodes.

By default, ZGC enables NUMA support, allowing it to leverage the benefits of NUMA architectures. It automatically detects and utilizes local memory nodes to optimize memory access and improve performance. However, if the JVM detects that it’s bound to use memory on a single NUMA node, NUMA support will be disabled.

In most cases, you don’t need to explicitly configure NUMA support. However, if you want to override the JVM’s decision, you can use the following options:

To explicitly enable NUMA support: -XX:+UseNUMA

To explicitly disable NUMA support: -XX:-UseNUMA


28 Mayıs 2019 Salı

G1 (Garbage-First) Garbage Collector - Java 9 ile Default Oldu

Giriş
G1 uzun bir aradan sonra çıkan bir garbage collector. Açıklaması şöyle.
Serial GC was the first garbage collector introduced in HotSpot in 1999 as part of Java Development Kit (JDK) 1.3.1. The Parallel and Concurrent Mark Sweep collectors were introduced in 2002 as part of JDK 1.4.2.
Ne Zaman Kullanılır
Açıklaması şöyle. 6GB'den büyük heap varsa kullanılır. Java 15'ten sonra Z GC kullanılıyor
The G1 Garbage Collector is a heavy duty GC designed for big workloads on machines with large heap sizes (roughly 6GB or higher). It tries to adapt to the working conditions in the given machine. You can explicitly enable it using the JVM option -XX:+UseG1GC.

G1 is a concurrent GC that works in the background and minimizes pauses. One of it’s cooler features is string de-duplication which reduces the overhead of strings in RAM. You can activate that feature using -XX:+UseStringDeduplication.
Bir diğer açıklama şöyle. Yani G1 GC daha fazla işlemci kullanıyor. Dolayısıyla G1 GC çok işlemcili ve yüksek miktarda belleğe sahip bilgisayarlar için tasarlanmış ve concurrent olarak çalışıyor.
Since Java 9, the G1 collector has been the default GC, the main idea being to slice up GC pauses according to user-supplied time targets. It usually offers shorter pause times but at the expense of lesser throughput. In addition, the pause time increases with the size of the heap.
Java 8 İle Geliyor, Java 9 ile Default Oldu
G1 kelimesi Garbage-First anlamına gelir. G1 Garbage Collector' ın bundan önceki Serial, Parallel ve CMS (Concurrent Mark And Sweep) garbage collector'lardan daha iyi olduğu söyleniyor. Sebebi ise daha tahmin edilebilir duraklama/gecikme (predictable latency) süresi. Açıklaması şöyle. Yani örneğin en fazla 10 ms Garbage Collection süresi istiyorsak bu süreyi tutturma olasılığımız diğer GC yöntemlerine göre daha yüksek bir ihtimal. 
The improvement over the CMS collector is called the G1 collector. Instead of having specific young and old generations for Heap this collector uses its entire heap and divides it into multiple regions. It has more footprint and the advantage of this collector is it has the most predictable latency and this is the best feature of this collector. When we start our application, we can pass on this variable that the maximum pause time (maxTargetPauseTime) that our application can withstand say 10ms for example. The G1 collector will try to ensure that the Garbage collection is done only for 10 ms and even if there is some garbage left it will take care in the next cycle. If we want the predictable latencies and pause times the G1 collector will be the best collector to use. This is the most commonly used collector for all the performance testing needs.
Java 10 ile İyileştirme - Parallel Full GC for G1 (JEP 307)
Açıklaması şöyle. Yani Full GC başlayınca artık paralel olarak yapılıyor.
Another interesting feature which improves G1 worst-case latencies by making the full GC parallel.

If you remember, In Java 9 release, G1 was made the default GC for JVM, which was designed to avoid full GC, but when the concurrent collections couldn’t reclaim memory quick enough it would end up falling back on a full GC, and that creates a problem.

This change will parallelize the full GC algorithm so that in the unlikely event of a G1 Full GC, same number of threads can be used as in the concurrent collections to improve the overall performance.
Bir başka açıklama şöyle
Till Java 10, G1 garbage collector was being used as primary concurrent garbage collector. Java 10 offered parallel full GC for garbage-first (G1) GCs, improving its worst-case latency. It also improved source code isolation of multiple GCs for the GC code in HotSpot, introducing the GC interface. But, all these changes didn’t resolve the most important issues like long GC pauses with Garbage collector in Java.
Ancak
Her iki iyileştirme de stop-the-world durumunda istenilen şeyi tam olarak sağlamadı. Bu yüzden Java 11 ile ZGC geldi.

Region Nedir?
Açıklaması şöyle
By design, the G1 garbage collector manages the heap by dividing it into a fixed number of same-size regions. By default, the maximum number of regions is 2048, and region size corresponds to the maximum heap size as follows: heap size < 4GB: 2MB, <8GB: 4MB, <16GB: 8MB, and so on. Normally objects are allocated into a given region until it's full, and then at some point, the GC frees up the entire region by evacuating all live objects from it.
Şeklen şöyle

Region dizilimi de şeklen şöyledir. Burada Eden + Survivor alanları Young Generation olarak bilinir. Old Generation mavi renkte. Humongous nesneler Free Space olarak tanımlanan gri renkli alanlara yerleşirler.


Burada önemli olan şey gri renkteki Free Space alanların gerektiğinde Eden veya Survivor veya Old Generation veya Humongous alan olarak kullanılabilmesi. Ayrıca aynı tipteki region'ların ardışık/yan yana olması gerekmiyor. Açıklaması şöyle
The heap is partitioned into a set of equal-sized heap regions, each a contiguous range of virtual memory. Certain region sets are assigned the same roles (eden, survivor, old) as in the older collectors, but there is not a fixed size for them. This provides greater flexibility in memory usage.
Eskiden bu alanların büyüklüğü sabitti. Şeklen şöyleydi.


Humongous Object Nedir
Açıklaması şöyle. Region büyüklüğünün yarısına eşit veya daha büyük nesne Humongous nesne kabul edilir.
All these changes, however, if an object (typically an array) is bigger than half the region size. Such objects are called Humongous in G1 terminology, and are handled as follows:

1. A humongous object is allocated directly in the Old Generation (note that this may or may not the case in JDK 11 and newer).

2. A separate humongous region is created for each such object by concatenating several contiguous regions. Some of these regions may need to be GCed first.

3. Each humongous region can accommodate only one Humongous object and nothing else. That is, the space between the end of the humongous object and the end of the humongous region (which in the worst case can be close to half the normal region size) is unused (this is true at least in JDK 8-11, but may be addressed in latest JDK versions) 
Humongous Object Neden Zararlı?
1. Humongous Object yerleştiği Region'ın geri kalanının kullanılmasını engelliyor. Bu yüzden heap içinde parçalanmaya sebep oluyor. Açıklaması şöyle. 
If the regions contain humongous objects, space between the last humongous object in the region and the end of the region will be unused. For example, our 550KB object prevents any other objects from being stored in the 1MB region, meaning 450KB remains unused. When we have lots of these objects, it results in a great deal of unused space and creates fragmentation.
Örnek
Açıklaması şöyle
If allocated in the Old Gen, they cannot be GCed quickly even if they are short-lived (the Old Gen is collected less frequently than the Young Gen, and it takes more time)
Creating a humongous region out of several normal regions may need a non-trivial amount of time
If there are many humongous objects on the heap, it can lead to heap fragmentation because of unused "gaps" in humongous regions.
2. Eski bir JVM kullanıyorsak ve sürekli Humongous nesne yaratırsak bir zaman sonra Free Space biter ve mecburen Full GC yapmak zorunda kalırız. Bir başka açıklama şöyle. 
Until Java 1.8u40, the releasing of humongous regions was only done during full GC events.
Humongous nesneden dolayı sürekli Full GC yapılmasını açıklayan bir yaz burada. Daha sonra bu durum düzeltildi. Açıklaması şöyle  
We have Java less than Oracle JDK 8u45 version. For Java greater than this, it is written in the release notes that these humongous objects also get collected in minor events.

Search for: “G1 now collects unreachable Humongous objects during young collections” in the Release Notes


G1 Seçenekleri
G1 için tüm seçenekler burada.

Seçenekler üç başlık altında toplanabilir.
- GC logging options - G1 Garbage Collector - Loglama Seçenekleri yazısına taşıdım
- JVM sizing options - Seçenekler burada.
- G1C options - G1 Garbage Collector Seçenekleri yazısına taşıdım.

Seçenek Sayısı
Tablo şöyle. GC CMS'e göre daha az seçenek kullanıyor yani daha basit
GC Algorithm   JVM arguments(approximately)
Common to all 50
Parallel      6
CMS            72
G1            26
ZGC            8
Açıklaması şöyle.
One of the main design points for G1 was to simplify the tuning required to realize good performance. For instance, the major inputs into G1 are the initial and maximum Java heap size it can use, and a maximum GC pause time you are willing to tolerate. From there G1 will attempt to adaptively adjust to meet those inputs while it executes your application.
G1 Kullanıldığını Teyit Etmek
Şöyle yaparız.
java -XX:+PrintFlagsFinal -version |
grep -E "MAX|UseSerialGC|UseG1GC|MaxHeapSize)"
Çıktı olarak şunu alırız.
size_t MaxHeapSize    = 268435456     {product} {ergonomic}
bool UseG1GC        = true         {product} {default}
bool UseSerialGC    = false          {product} {ergonomic}
XX:+UseG1GC seçeneği
Use the Garbage First (G1) Collector
Eskiden olduğu gibi +UseXXXGC şeklindeki kullanım devam ediyor. Şöyle yaparız.
-XX:+AlwaysPreTouch 
-XX:CICompilerCount=15 
-XX:ConcGCThreads=6 
-XX:G1HeapRegionSize=16777216 
-XX:GCLogFileSize=10485760 
-XX:+HeapDumpOnOutOfMemoryError 
-XX:InitialHeapSize=48318382080 
-XX:MarkStackSize=4194304 
-XX:MaxHeapSize=48318382080 
-XX:MaxNewSize=28991029248 
-XX:MinHeapDeltaBytes=16777216 
-XX:NumberOfGCLogFiles=5 
-XX:-OmitStackTraceInFastThrow 
-XX:OnOutOfMemoryError=/bin/kill -9 %p 
-XX:+PrintGC -XX:+PrintGCApplicationStoppedTime 
-XX:+PrintGCDateStamps 
-XX:+PrintGCDetails 
-XX:+PrintGCTimeStamps 
-XX:+PrintTenuringDistribution 
-XX:+UseG1GC <------------------------------------Burası 
-XX:+UseGCLogFileRotation
Young GC Safhası
Bu safhada "Stop the World" yaklaşımı ile her şey durdurulur. MaxGCPauseMillis değeri dikkate alınarak şu iş yapılır. Bu işleri yapmak için çok sayıda thread kullanılır.

1. Hayatta kalan nesneler Survivor alanına taşınır.
2. Yaşlılık kriterini geçen bazı nesneler ise Old Generation alanına taşınır.

Old GC Safhası
Bu safha daha fazla adımdan oluşuyor. Tüm adımlar burada. Bu safhada da "Stop the World" yaklaşımı ile her şey durdurulur.