1. Zibil toplayıcı (GC) ilə tanışlıq
Əgər nə vaxtsa C və ya C++‑da yazmısınızsa, yəqin ki, yaddaşı əl ilə free() və ya delete vasitəsilə azad etmək zərurəti ilə qarşılaşmısınız. Java‑da hər şey daha sadədir: obyekti new ilə yaradırsınız, silməyə ehtiyac yoxdur — bununla zibil toplayıcı (Garbage Collector, GC) adlanan xüsusi “təmizlikçi” məşğul olur.
GC — JVM-in bir hissəsidir və artıq istinad olunmayan obyektlərin tutduğu yaddaşı avtomatik azad edir. Bunun sayəsində Java‑tərtibatçıları yaddaşı təmizləməyi unutmaqdan (və sızma almaqdan) ya da əksinə, hələ lazım olan obyekti təsadüfən silib qəza (crash) almaqdan narahat olmurlar.
Lakin hər bir “təmizlikçi” kimi GC də ideal deyil: bəzən ən uyğun olmayan anda “başdan‑ayağa təmizlik” (Stop-the-World) edə bilər və ya istədiyiniz qədər sürətli işləməyə bilər. Buna görə JVM-də zibil toplayıcının bir neçə fərqli reallaşdırması mövcuddur — düzgün seçimin edilməsi tətbiqin məhsuldarlığına ciddi təsir göstərə bilər.
Əsas zibil toplayıcı tipləri
Serial GC
- Serial GC — ən sadə və ən köhnə zibil toplayıcıdır.
- Bir axında işləyir.
- Təmizlik zamanı digər bütün axınları dayandırır (Stop-the-World).
- Aktiv çoxaxınlılıq olmayan kiçik tətbiqlər üçün uyğundur.
- Flaq ilə qoşulur: -XX:+UseSerialGC
Parallel GC
- Parallel GC (həmçinin “Throughput Collector”).
- Zibili toplamaq üçün bir neçə axından istifadə edir.
- Maksimal keçiriciliyə yönəlib.
- Yenə də Stop-the-World pauzaları ilə təmizləmə aparır, amma Serial-dən daha sürətlidir.
- Kiçik pauzaların kritik olmadığı server tətbiqləri üçün uyğundur.
- Flaq ilə qoşulur: -XX:+UseParallelGC
CMS (Concurrent Mark Sweep)
- CMS — köhnəlmiş, lakin uzun müddət populyar olmuş, pauzaları minimuma endirən GC.
- Tətbiqlə qismən paralel işləyir, dayanma vaxtını azaldır.
- Daha mürəkkəb tənzimlənir, əlavə xərci (overhead) var.
- Java 9‑dan etibarən köhnəlmiş (deprecated) kimi işarələnib.
- Flaq ilə qoşulur: -XX:+UseConcMarkSweepGC
G1 (Garbage First)
- G1 GC — müasir, defolt zibil toplayıcı (Java 9‑dan başlayaraq).
- Pauzaları minimuma endirmə və məhsuldarlıq arasında balans yaradır.
- Yığını çoxsaylı kiçik regionlara bölür (regional model).
- Yığını bütöv yox, seçmə regionlar üzrə toplaya bilər.
- Maksimal pauza hədəfini təyin etməyə imkan verir, məsələn -XX:MaxGCPauseMillis=200.
- Qoşma flaqı: -XX:+UseG1GC (adətən lazım deyil, çünki G1 defoltdur).
ZGC və Shenandoah
- ZGC və Shenandoah — müasir low‑latency zibil toplayıcıları.
- Məqsəd — minimal pauzalar (millisaniyələr), hətta nəhəng yığınlarda (TB‑lara qədər).
- Demək olar ki, tam şəkildə tətbiqlə paralel işləyirlər.
- Java 11+ (ZGC) və ya Java 12+ (Shenandoah) tələb edir.
- Latency‑critical sistemlər üçün uyğundur (birjalar, fintex, real‑time analitika).
- Qoşma flaqları: -XX:+UseZGC və ya -XX:+UseShenandoahGC
3. Müasir GC‑lərin iş prinsipləri
Gənc və köhnə nəsil (Young/Old Generation)
JVM yığını iki böyük hissəyə bölür:
Gənc nəsil (Young Generation): bütün yeni obyektlər bura düşür. Burada təmizləmə tez‑tez və sürətlə baş verir ( Minor GC ).
Köhnə nəsil (Old Generation, Tenured): gənc nəsildə bir neçə təmizləmədən “sağ çıxan” obyektlər bura köçürülür. Burada təmizləmə daha nadir, lakin daha uzun çəkir ( Major/Full GC ).
Niyə belədir? Java‑da obyektlərin çoxu çox qısaömürlüdür (məsələn, müvəqqəti sətirlər, metod daxilində kolleksiyalar). Buna görə gənc nəsli tez‑tez və sürətlə təmizləmək, köhnə nəsilə toxunmadan mümkündür.
Minor GC
- Yalnız gənc nəsili təmizləyir.
- Sürətlidir, qısa pauza ilə.
- Köhnə obyektlərə toxunmur.
Major (Full) GC
- Bütöv yığını (həm gənc, həm köhnə nəsli) təmizləyir.
- Çox vaxt apara bilər (böyük yığınlarda saniyələr və daha çox).
- Adətən tətbiqin uzun pauzası ilə müşayiət olunur.
GC hansı obyektləri siləcəyini necə müəyyənləşdirir?
GC “canlı” obyektləri kök istinadlardan (root set) başlayaraq axtarır: axın steklərindəki lokal dəyişənlər, statik sahələr, metod parametrləri və s. Nəyə “çatmaq” mümkündürsə, canlı sayılır. Qalanı — zibildir.
4. Müasir toplayıcıların müqayisəsi: G1, ZGC, Shenandoah
Gəlin ən müasir və populyar GC‑lərin fərqlərini anlayaq. Bunun üçün aydın bir cədvəl:
| Toplayıcı | Əsas məqsəd | Yaddaş modeli | Minimal pauzalar | Miqyaslana bilmə | Dəstək | Nə vaxt istifadə etməli |
|---|---|---|---|---|---|---|
| G1 | Pauza/sürət balansı | Regionlar | ~10–200 ms | Yüzlərlə GB‑a qədər | Java 9+ (defolt) | Server tətbiqlərinin əksəriyyəti |
| ZGC | Minimal pauza | Regionlar, “rəngli nişanlar” | <10 ms | TB‑lara qədər | Java 11+ | Real vaxt, latency‑critical |
| Shenandoah | Minimal pauza | Regionlar, “rəngli nişanlar” | <10 ms | TB‑lara qədər | Java 12+ (RedHat) | Real vaxt, latency‑critical |
G1 GC: Garbage First
- Yığını çoxsaylı regionlara bölür (adətən hər biri 1–32 MB).
- Təmizlik zamanı ən çox zibil olan regionları seçir (“garbage first”).
- Yığını tam yox, yalnız bir hissəsini toplaya bilər.
- Hədəf pauzanı təyin etməyə imkan verir: -XX:MaxGCPauseMillis=200.
- Sürət və pauzalar arasında balans üçün uyğundur; Java 9‑dan etibarən defolt olaraq istifadə olunur.
Qoşma nümunəsi (əgər birdən söndürülübsə):
java -XX:+UseG1GC -jar myapp.jar
ZGC: Z Garbage Collector
- Java 11‑də eksperimental, Java 15‑dən stabil.
- Tətbiqi demək olar ki, dayandırmır: pauzalar adətən <10 ms olur, hətta 1–2 TB yığınlarda.
- “Rəngli nişanlar” (coloring) və xüsusi göstəricilər istifadə edir.
- 64‑bit JVM tələb edir; 32‑bit sistemlərdə işləmir.
- Linux, macOS, Windows üzərində dəstəklənir.
Qoşma nümunəsi:
java -XX:+UseZGC -jar myapp.jar
Shenandoah
- RedHat tərəfindən hazırlanıb; məqsədlər ZGC‑yə bənzəyir.
- Minimal pauzalar, tətbiqlə aktiv paralel iş.
- Linux və Windows dəstəyi; OpenJDK yığımlarının bir hissəsi.
- Bənzər texnikalardan istifadə edir, lakin daxili alqoritmləri fərqlidir.
Qoşma nümunəsi:
java -XX:+UseShenandoahGC -jar myapp.jar
Vizual müqayisə
graph TD
A[Gənc nəsil] -->|Minor GC| B[Köhnə nəsil]
B -->|Major GC| C[GC pauzası]
D[G1: regionlar] --> E[Seçmə regionlar]
F[ZGC/Shenandoah: regionlar] --> G[Paralel təmizləmə]
5. Təcrübə: GC‑ni necə öyrənmək və dəyişmək olar
Hansı GC‑nin istifadə olunduğunu necə bilmək olar?
- JVM jurnalları: Tətbiqi -Xlog:gc* (Java 9+) və ya -verbose:gc (Java 8‑ə qədər) parametrləri ilə işə salın. Jurnallarda hansı GC‑nin istifadə olunduğu və pauzaların nə qədər tez‑tez baş verdiyi görünəcək.
- jcmd: İcra edin:
harada <pid> — Java prosesinin ID‑sidir.jcmd <pid> VM.flags - jvisualvm: “Monitoring” bölməsində GC tipini görə bilərsiniz.
Tətbiqiniz üçün GC‑ni necə dəyişmək olar?
Java‑proqramını işə salarkən lazım olan flaqı əlavə edin:
G1 GC (defolt, amma açıq şəkildə göstərmək olar):
java -XX:+UseG1GC -jar myapp.jar
ZGC:
java -XX:+UseZGC -jar myapp.jar
Shenandoah:
java -XX:+UseShenandoahGC -jar myapp.jar
Yığın ölçüsünü və pauzaları necə təyin etməli?
- Maksimal yığın ölçüsü: -Xmx2G
- Minimal yığın ölçüsü: -Xms512M
- G1 üçün: arzu olunan pauza — -XX:MaxGCPauseMillis=200
Tam işə salma nümunəsi:
java -Xms512M -Xmx2G -XX:+UseG1GC -XX:MaxGCPauseMillis=100 -jar myapp.jar
6. Müxtəlif tapşırıqlar üçün GC seçiminin xüsusiyyətləri
G1 nə vaxt seçilməlidir
- Əksər server və desktop tətbiqlərində — defolt olaraq əla seçimdir.
- Yüzlərlə meqabaytdan yüzlərlə gigabayta qədər yığınlarda yaxşı işləyir.
- Sürət və pauzalar arasında balans yaradır.
ZGC və ya Shenandoah nə vaxt seçilməlidir
- Tətbiq gecikməyə həssasdırsa (latency‑critical: birjalar, onlayn oyunlar, real‑time analitika).
- Yığın çox böyükdürsə (yüzlərlə gigabayt və daha çox).
- Yalnız minimal pauzalar (millisaniyələr) məqbuldursa.
- Java 11+ (ZGC) və ya Java 12+ (Shenandoah) tələb olunur.
Parallel GC nə vaxt kifayətdir
- Maksimal keçiricilik vacib, pauzalar isə qeyri‑kritik olan kiçik tətbiqlər üçün.
- Pauzanı “dözüb keçmək” mümkün olan batch emalda, Full GC zamanı.
7. Nümunə: sadə tətbiqdə GC davranışının müqayisəsi
Çoxlu müvəqqəti obyekt yaradan kiçik bir tətbiq (sifarişlərin emalının simulyasiyası):
public class GCSimulator {
public static void main(String[] args) {
while (true) {
// Hər dövrdə 100 000 obyekt yaradırıq
for (int i = 0; i < 100_000; i++) {
String s = new String("Order-" + i);
}
// Bir az dincəlirik
try { Thread.sleep(100); } catch (InterruptedException e) {}
}
}
}
Onu müxtəlif GC‑lərlə işə salın və jurnallara baxın:
java -Xmx256M -XX:+UseG1GC -Xlog:gc* GCSimulator
java -Xmx256M -XX:+UseZGC -Xlog:gc* GCSimulator
Nə görəcəksiniz?
G1 tez‑tez, lakin qısa pauzalar edəcək. ZGC/Shenandoah — pauzalar daha da qısa olacaq, amma daha tez‑tez baş verə bilər. Parallel GC — pauzalar daha uzun, amma daha seyrək.
8. GC ilə işləyərkən tipik səhvlər və nüanslar
Xəta №1: GC‑nin yaddaşla bağlı bütün problemləri həll edəcəyini gözləmək. GC — sehrli çubuq deyil. Lazımsız obyektlərə istinadları saxlayırsınızsa, heç bir GC kömək etməyəcək — yaddaş sızması olacaq.
Xəta №2: Məcburi System.gc() çağırışı. JVM zibili nə vaxt toplamağı daha yaxşı bilir. Məcburi GC uzun pauzaya səbəb ola və məhsuldarlığı azalda bilər.
Xəta №3: GC jurnallarını görməməzlikdən gəlmək. GC jurnallarına baxmasanız, tətbiqinizin mütəmadi olaraq Full GC zamanı “donduğunu” görməyə bilərsiniz.
Xəta №4: Köhnəlmiş GC‑lərdən istifadə. Məsələn, CMS artıq inkişaf etdirilmir. Daha yaxşısı G1 və ya müasir low‑latency toplayıcılara keçməkdir.
Xəta №5: Tapşırıq üçün GC‑nin yanlış seçimi. Əgər tətbiqiniz latency‑critical‑dirsə, siz isə Parallel GC istifadə edirsinizsə — uzun pauzaları gözləyin. Batch emalınız varsa və ZGC qoşmusunuzsa — əlavə overhead əldə edəcəksiniz.
GO TO FULL VERSION