Masalah dan Senario yang Berkenaan
API Java yang sensitif terhadap kependaman berjalan pada HotSpot JDK 25 dengan G1 dan timbunan (heap) tetap bersaiz 12 GiB: -Xms12g -Xmx12g. Selepas ciri cache dilancarkan, p99 permintaan meningkat daripada 120 milisaat kepada 2–4 saat setiap 3–5 minit. CPU hos tidak tepu semasa lonjakan berlaku. Pemantauan juga menunjukkan bahawa penggunaan generasi lama selepas pengutipan meningkat daripada 6.1 GiB kepada 9.2 GiB dalam tempoh dua jam, manakala kadar peruntukan aplikasi meningkat daripada kira-kira 600 MiB/s kepada 1.4 GiB/s. Pasukan melabelkan insiden tersebut sebagai "masalah GC" dan mencadangkan untuk meningkatkan timbunan kepada 24 GiB terlebih dahulu.
Semua angka adalah andaian temu duga. Calon mesti menerangkan cara untuk membuktikan sama ada lonjakan kependaman benar-benar sepadan dengan jeda JVM; cara menggunakan pengelogan GC disatukan (unified GC logging), Java Flight Recorder (JFR), dan diagnostik timbunan terhad untuk membezakan kadar peruntukan yang tinggi, pertumbuhan set hidup, objek humongous G1, System.gc() eksplisit, dan titik selamat bukan GC; serta cara menghasilkan pelan pemulihan dan pengesahan yang boleh diterbalikkan. Matlamatnya bukan untuk menghafal bendera pengutip. Ia adalah untuk membina rantaian sebab dan akibat daripada gejala kepada bukti, hipotesis, eksperimen, dan SLO.
Bahan temu duga GC Java awam menganggap peristiwa hentikan-dunia (stop-the-world) dan masa jeda JVM sebagai topik teras. Panduan HotSpot Oracle untuk penyelesaian masalah jeda panjang secara langsung merangkumi timbunan yang tidak mencukupi, pemecahan timbunan, aktiviti sistem pengendalian, dan GC eksplisit. Sumber-sumber tersebut menjadikan ini soalan diagnostik prestasi JVM yang representatif. Tiada atribusi syarikat yang boleh dipercayai adalah awam, jadi companyName dibiarkan kosong.
Perkara yang Diuji oleh Penemu Duga
Isyarat pertama ialah sama ada calon menyelaraskan garis masa sebelum melakukan penalaan. p99 Permintaan, log GC JVM, peristiwa JFR, pendikit CPU kontena, peristiwa cakera, dan metrik hos memerlukan asas masa yang sama. Graf timbunan berbentuk gigi gergaji (sawtooth) hanya membuktikan bahawa pengutipan telah berlaku; ia tidak membuktikan bahawa lonjakan permintaan tiga saat tertentu disebabkan oleh GC. Sebaliknya, G1 melakukan kerja serentak (concurrent) yang banyak, jadi kitaran GC yang panjang tidak bermakna aplikasi dijeda sepanjang keseluruhan kitaran tersebut.
Isyarat kedua ialah sama ada calon memisahkan jeda individu yang terlalu panjang daripada nisbah jumlah jeda yang berlebihan. Yang pertama memerlukan jenis jeda dan pemasaan fasa, data hidup sebelum/selepas, bait yang disalin, dan pemasaan OS. Yang kedua sering kali menjejaki kadar peruntukan dan kekerapan pengutipan. Purata tempoh GC sahaja menyembunyikan kedua-dua jeda ekor (tail pauses) yang jarang berlaku dan sejumlah besar jeda pendek.
Isyarat ketiga ialah sama ada bukti yang memilih langkah pemulihan. Tekanan peruntukan memerlukan pencarian titik panas peruntukan. Garis dasar old-after-GC yang meningkat memerlukan bukti bahawa objek yang tidak diingini kekal boleh dicapai. Pertumbuhan dalam Humongous regions memerlukan penjejakan objek yang melebihi separuh rantau G1. Sebab log System.gc() memerlukan pencarian pemanggil. "Tingkatkan timbunan, kurangkan sasaran jeda, atau tukar kepada ZGC" bukanlah diagnosis yang sesuai untuk setiap gejala.
Akhir sekali, penemu duga menguji kesedaran risiko pengeluaran. Statistik timbunan JFR mencetuskan pengutipan lama tambahan. Oracle menandakan jcmd GC.class_histogram dan lambakan timbunan (heap dumps) sebagai operasi berimpak tinggi, dan lambakan timbunan meminta Full GC secara lalai. Jawapan yang kukuh mengumpul bukti beroverhed rendah terlebih dahulu, memperoleh bukti berimpak berat pada replika, di luar waktu puncak, atau dalam persekitaran terkawal, dan menggunakan kenari (canary) dengan beban yang sama untuk membuktikan bahawa jeda yang lebih rendah tidak ditebus dengan daya pemprosesan, CPU, atau memori yang tidak boleh diterima.
Soalan untuk Dijelaskan Sebelum Menjawab
- Apakah sebenarnya yang "terhenti" (stalled)? Adakah ia kependaman pengendali pelayan, kependaman hujung-ke-hujung klien, semua urutan
Java tidak membuat kemajuan, atau hanya beberapa permintaan yang beratur? Adakah lonjakan terpencil kepada satu tika (instance), dan adakah pengimbang beban, kebergantungan, atau rangkaian menunjukkan peristiwa yang sama?
- Bolehkah log dan metrik dikorelasikan dengan tepat? Kami memerlukan ID tika, cap masa UTC, masa hidup (uptime) JVM,
dan versi keluaran yang sama. Jika log hanya mempunyai cap masa peringkat minit, tingkatkan kebolehmerhatian sebelum membuat kesimpulan daripada dua keluk yang sekadar kelihatan serupa.
- Apakah yang terkandung dalam log G1? Sekurang-kurangnya, kekalkan ID GC, sebab, jenis jeda, timbunan sebelum dan selepas,
serta tempoh. Dayakan gc+heap, gc+phases, dan gc+cpu apabila diperlukan. RSS proses atau peratusan timbunan sahaja tidak mencukupi.
- Adakah garis dasar generasi lama pasca-pengutipan terus meningkat di bawah beban yang setanding? Dataran tinggi (plateau)
selepas pemanasan cache mungkin merupakan set hidup yang dijangkakan. Pertumbuhan berterusan dengan bait ditebus yang berkurangan adalah lebih konsisten dengan pengekalan (retention) atau kebocoran memori.
- Apakah had yang dikenakan pada kontena dan hos? Periksa kuota dan pendikit CPU, swap, ralat halaman (page faults),
tekanan memori, I/O log menyekat, dan jiran bising (noisy neighbors). Masa dinding (wall time) GC yang panjang dengan masa CPU yang sedikit mungkin bermakna JVM telah dinyahjadualkan atau halamannya telah di-swap keluar.
- Hubungan peruntukan dan rujukan manakah yang berubah dalam keluaran tersebut? Periksa kapasiti cache,
TTL, saiz kunci dan nilai, penimbal penyerian (serialization buffers), saiz kelompok, keserentakan, dan pengekalan melalui ThreadLocals, pendengar (listeners), giliran, atau koleksi statik.
- Apakah matlamat kependaman dan daya pemprosesan? Tentukan p99 dan maksima jeda, p99 permintaan, daya pemprosesan,
kadar ralat, had CPU, dan had memori. -XX:MaxGCPauseMillis ialah petunjuk matlamat untuk G1, bukan batas mutlak pada setiap jeda.
- Bolehkah bukti berimpak berat dikumpulkan dengan selamat? Jika hanya ada satu tika pengeluaran, tambah
kapasiti atau alirkan keluar (drain) trafik terlebih dahulu. Jangan lambakkan timbunan 12 GiB semasa insiden dan kemudian tersalah anggap Full GC diagnostik sebagai kegagalan asal.
Rangka Kerja Jawapan 30 Saat
"Saya tidak akan mengubah timbunan terlebih dahulu. Saya akan mengkorelasikan setiap lonjakan permintaan, mengikut tika dan cap masa, dengan -Xlog:gc*, peristiwa JFR jdk.GCPhasePause, pendikit CPU, ralat halaman, dan kependaman kebergantungan untuk mengukur berapa lama aplikasi sebenarnya berhenti. Kemudian saya akan membahagikan bukti kepada tiga kumpulan: jenis dan fasa setiap jeda; jumlah nisbah jeda bagi setiap tetingkap masa; dan trend dalam kadar peruntukan, kadar promosi, penggunaan old-after-GC, dan rantau humongous.
Jika cache meningkatkan peruntukan tetapi garis dasar pasca-pengutipan adalah stabil, saya akan menggunakan JFR untuk mencari titik panas peruntukan dan mengurangkan objek sementara. Jika old-after-GC terus meningkat, saya akan membandingkan histogram kelas dan mendapatkan lambakan timbunan pada replika terkawal untuk memeriksa dominator dan laluan pengekalan. Jika Full GC didahului oleh kegagalan pemindahan (evacuation failures) atau banyak rantau humongous, saya akan memeriksa dan membahagikan tatasusunan besar, penimbal, dan kelompok. Jika puncanya ialah System.gc(), saya akan mengenal pasti pemanggil. Setiap perubahan akan diuji dalam kenari berbeban sama terhadap p99 permintaan, p99 dan maksima jeda, jumlah nisbah jeda, kadar peruntukan, set hidup pasca-pengutipan, CPU, daya pemprosesan, dan ralat sebelum dilancarkan sepenuhnya."
Penyelaman Mendalam Langkah demi Langkah
Langkah 1: Bina garis masa yang boleh dibuktikan palsu (falsifiable) dan buktikan sama ada GC terlibat.
Bagi setiap lonjakan kependaman, rekodkan tika, tetingkap permintaan, versi keluaran, dan masa UTC. Korelasikannya dengan pengelogan disatukan dan peristiwa jeda JFR mengikut ID GC. Konfigurasi permulaan garis dasar boleh mengekalkan data GC dan titik selamat bercap masa dan berteg dalam fail yang berputar (rotating files):
-Xlog:gc*,safepoint:file=/var/log/app/gc-%p.log:time,uptime,level,tags:filecount=10,filesize=100mIni ialah contoh diagnostik; sesuaikan laluan, pengekalan, dan belanjawan cakera mengikut persekitaran. Dalam JFR, fokus pada tempoh jdk.GCPhasePause sambil turut memeriksa beban CPU, urutan, I/O soket/fail, dan peristiwa peruntukan. Panduan Oracle menyatakan bahawa, bagi pengutip serentak, jumlah panjang kitaran adalah kurang bermakna berbanding masa aplikasi sebenarnya dijeda.
Cipta tiga cabang hasil. Jika lonjakan sejajar satu-dengan-satu dengan jeda JVM, teruskan ke analisis punca utama GC. Jika jeda GC yang dilaporkan adalah pendek tetapi titik selamat adalah panjang, periksa sebab titik selamat dan masa yang diambil untuk mencapainya. Jika tiada satu pun yang sejajar, siasat pendikit CPU, kunci (locks), I/O, rangkaian, dan perkhidmatan hilir. Ini menjadikan hipotesis GC boleh dibuktikan palsu dan bukannya penjelasan lalai untuk semua kependaman.
Langkah 2: Huraikan gejala GC dengan set metrik, bukan satu graf sahaja.
Kekalkan sekurang-kurangnya siri masa berikut dan bandingkan tetingkap beban yang sama sebelum dan selepas keluaran:
Requests: p50 / p95 / p99 / max, throughput, timeouts, error rate
Pauses: pause p50 / p95 / p99 / max, paused time per minute, pause cause
Heap: young / old usage, old-after-GC, reclaimed bytes, promotion rate
Allocation: bytes/s, top allocation sites by class and thread, inside/outside TLAB
G1: young / mixed / Full counts, evacuation failures, humongous regions
System: process CPU, GC CPU, CPU throttling, RSS, swap, major page faults, disk latencyFormat used-before → used-after (heap-capacity) menunjukkan apa yang ditebus oleh satu pengutipan, tetapi satu titik bukanlah satu trend. Garis dasar old-after-GC yang meningkat secara monotonik pada beban yang setanding mencadangkan pertumbuhan dalam set hidup atau tekanan promosi. Garis dasar yang stabil dengan pengutipan yang semakin kerap lebih sering menunjukkan peruntukan yang tinggi. Apabila gc+cpu=info menunjukkan masa nyata (real time) jauh melebihi masa pengguna ditambah sistem, siasat penjadualan, kuota, atau paging sebelum menambah urutan GC.
Langkah 3: Gunakan bukti untuk memisahkan lima laluan punca utama.
- Kadar peruntukan yang tinggi. Old-after-GC adalah stabil, manakala kiraan jeda muda (young-pause) dan masa jeda seminit
meningkat. Peristiwa peruntukan JFR menunjukkan kepada pembinaan kunci cache, penyerian, atau koleksi sementara. Kurangkan penyalinan, gunakan semula penimbal dengan kitaran hayat yang jelas, dan kawal saiz kelompok. Jangan perkenalkan pengumpulan objek (object pooling) yang luas dan keadaan dikongsi tanpa bukti.
- Pertumbuhan set hidup atau kebocoran memori. Old-after-GC terus meningkat dan setiap pengutipan menebus lebih sedikit.
Bandingkan histogram kelas pada pelbagai masa. Dapatkan lambakan timbunan hanya pada replika di luar waktu puncak atau dalam persekitaran main semula trafik, kemudian gunakan saiz tertahan (retained size), pepohon dominator, dan punca GC untuk membezakan cache yang sah daripada pengekalan tanpa batas. Cache yang mendatar pada kapasiti ialah isu saiz; objek tamat tempoh yang kekal dirujuk menunjukkan kebocoran.
- Objek humongous G1. G1 menganggap objek yang bersaiz sekurang-kurangnya separuh rantau sebagai humongous dan meletakkannya
terus dalam rantau lama yang bersebelahan. Jika Humongous regions: X → Y kekal tinggi, jejaki byte[] yang besar, char[], blok dimampatkan, atau kelompok dan kurangkan saiz objek atau kelompok individu terlebih dahulu. Anggap perubahan saiz rantau sebagai eksperimen hanya selepas pengukuran, kerana ia juga mengubah kiraan rantau dan granulariti pengutipan.
- Penandaan serentak (concurrent marking) ketinggalan atau pemindahan gagal. Jika log menunjukkan ruang destinasi
tidak mencukupi atau rantau yang tidak boleh dipindahkan, senario terburuk ialah Full GC untuk keseluruhan timbunan. Kurangkan peruntukan atau promosi rantau lama, berikan ruang legar (headroom) yang mencukupi untuk penandaan serentak, dan periksa margin keselamatan antara kapasiti timbunan dan set hidup. Mengurangkan MaxGCPauseMillis sahaja mungkin membuatkan setiap pengutipan melakukan kurang kerja dan membiarkan sistem lebih hampir kepada kehabisan sumber.
- GC eksplisit atau titik selamat bukan GC. Jika sebab GC ialah
System.gc(), gunakan timbunan panggilan (call stacks), konfigurasi
kebergantungan, dan arahan operasi untuk mencari sumber sebelum mengalih keluar panggilan, mengkonfigurasi pustaka, atau mengasingkan tugas. Gunakan DisableExplicitGC hanya selepas memeriksa impak semantik. Jika titik selamat adalah panjang tetapi jeda GC adalah pendek, periksa sebab sebenar—seperti deoptimuman, penakrifan semula kelas, atau operasi VM lain—dan bukannya menukar pengutip.
Langkah 4: Lapiskan alat diagnostik dan kawal risiko pemerhatian.
Mulakan dengan lapisan yang tersedia secara berterusan dan berkos lebih rendah: SLI aplikasi, log GC/titik selamat disatukan, dan JFR standard. Untuk pengesahan langsung, jalankan jcmd PID JFR.start, JFR.check, dan JFR.dump pada hos yang sama sebagai pengguna efektif yang sama. Periksa pilihan yang disokong oleh JVM tersebut terlebih dahulu dengan jcmd PID help COMMAND.
Kemudian beralih kepada lapisan berkos tinggi. Oracle menandakan GC.class_histogram sebagai berimpak tinggi. GC.heap_dump juga berimpak tinggi dan meminta Full GC secara lalai. Statistik timbunan JFR mencetuskan pengutipan lama tambahan pada permulaan dan penghujung, jadi jangan dayakan statistik timbunan secara lalai semasa penyiasatan kependaman. Alirkan keluar trafik atau hasilkan semula isu tersebut pada replika, sahkan kapasiti cakera dan pengendalian data sensitif, dan hanya selepas itu dapatkan histogram atau lambakan. Membandingkan dua tangkapan yang dipisahkan oleh selang beban yang stabil menerangkan pertumbuhan dengan lebih baik daripada satu senarai objek terbesar.
Langkah 5: Kekalkan sebab dan akibat yang tunggal apabila mengubah kod, kapasiti, atau tetapan pengutip.
Mulakan dengan cache baharu. Adakah ia tidak terhad? Adakah TTL-nya benar-benar menamatkan tempoh entri? Adakah berat maksimum diukur dalam bait dan bukannya kiraan entri? Adakah setiap nilai menyalin tatasusunan yang besar? Adakah ralat temu (misses) serentak membina nilai yang sama secara bebas? Pembetulan kod calon termasuk mengehadkan berat maksimum, menggabungkan pemuatan kunci yang sama, penyerian penstriman, mengurangkan saiz kelompok, atau menggugurkan rujukan kepada objek sementara lebih awal. Ubah satu pemboleh ubah utama dalam setiap eksperimen.
Timbunan yang lebih besar boleh meningkatkan selang antara pengutipan, tetapi ia juga boleh menyembunyikan pengekalan tanpa batas, meningkatkan risiko memori kontena, dan meningkatkan jumlah data hidup yang akhirnya mesti diproses. Sebelum mengubah IHOP, saiz generasi muda, saiz rantau, atau sasaran jeda, kenal pasti fasa yang dilog atau defisit sumber yang dijangka akan diubah oleh bendera tersebut. Beralih kepada pengutip seperti ZGC ialah eksperimen seni bina yang memerlukan daya pemprosesan, CPU, ruang legar timbunan, kontena, dan pengesahan operasi yang baharu. Ia bukan arahan insiden yang pertama.
Langkah 6: Tutup insiden dengan kenari berbeban sama dan bukti kontrafaktual.
Mainkan semula permintaan berbentuk pengeluaran, saiz objek, kadar kenaan cache (cache hit rate), dan keserentakan terhadap garis dasar dan versi yang telah dibetulkan. Kenari mesti merangkumi beberapa kitaran lonjakan asal 3–5 minit dan merangkumi permulaan sejuk cache serta keadaan stabil. Tentukan ambang penerimaan sebelum ujian, contohnya: p99 permintaan di bawah 200 ms; p99 jeda GC di bawah 100 ms dan maksima di bawah 500 ms; kurang daripada 1% masa dijeda seminit; old-after-GC tidak lagi meningkat selepas pemanasan; dan tiada kemerosotan dalam daya pemprosesan, belanjawan CPU, OOM, atau ralat.
Kemudian uji perkara kontrafaktual. Adakah mengembalikan semula (rolling back) cache memulihkan kedua-dua kadar peruntukan dan lonjakan? Adakah mengehadkan berat cache sahaja dapat menstabilkan old-after-GC? Adakah mengurangkan saiz kelompok sahaja dapat mengurangkan rantau humongous? Apabila metrik yang diramalkan bergerak bersama, langkah pemulihan mempunyai hubungan sebab dan akibat dengan punca utama. Lancarkan secara berperingkat dan kekalkan kriteria pembalikan automatik.
Contoh Jawapan Berkualiti Tinggi
"Data semasa menjadikan GC wajar disiasat, tetapi ia tidak membuktikan bahawa GC yang menyebabkan lonjakan permintaan 2–4 saat tersebut. Saya akan menyelaraskan SLI permintaan, -Xlog:gc*,safepoint, peristiwa JFR jdk.GCPhasePause, pendikit CPU, ralat halaman, dan kependaman kebergantungan mengikut tika dan masa UTC terlebih dahulu. Jika lonjakan sejajar dengan jeda, saya akan membezakan satu jeda panjang daripada banyak jeda pendek yang terkumpul. Jika hanya titik selamat yang panjang, saya akan menjejaki sebab titik selamat. Jika tiada satu pun yang sejajar, saya akan meninggalkan cabang GC.
Keluaran tersebut telah meningkatkan peruntukan daripada 600 MiB/s kepada 1.4 GiB/s manakala old-after-GC meningkat daripada 6.1 GiB kepada 9.2 GiB. Itu memberikan saya sekurang-kurangnya dua hipotesis: cache telah mencipta peruntukan sementara yang besar, dan cache atau objek yang berkaitan telah meluaskan set hidup. Saya akan memeriksa sebab-sebab young, mixed, dan Full; timbunan sebelum dan selepas; promosi; kegagalan pemindahan; dan rantau humongous. Peristiwa peruntukan JFR mengenal pasti kelas, urutan, dan tapak panggilan. Histogram daripada pelbagai masa menunjukkan kelas mana yang terus berkembang. Saya akan mendapatkan lambakan timbunan hanya pada replika yang telah dialirkan keluar atau dalam main semula kerana ia berimpak tinggi dan boleh meminta Full GC secara lalai.
Jika garis dasar pasca-pengutipan adalah stabil tetapi jeda muda kerap berlaku, saya akan mengurangkan peruntukan dalam pembinaan kunci cache, penyerian, dan koleksi sementara. Jika garis dasar terus meningkat, saya akan menggunakan saiz tertahan dan laluan punca GC untuk membezakan cache terhad daripada kebocoran. Jika tatasusunan besar melebihi separuh rantau G1 dan penggunaan rantau humongous meningkat, saya akan membahagikan penimbal atau kelompok. Jika puncanya ialah System.gc(), saya akan mencari pemanggil. Jika masa nyata jauh melebihi masa CPU GC, saya akan menyiasat kuota, swap, dan perebutan hos.
Saya tidak akan menganggap timbunan 24 GiB sebagai penyelesaian. Saya akan menguji setiap perubahan calon secara bebas dalam kenari berbeban sama merentasi permulaan sejuk cache dan beberapa kitaran lonjakan asal. Pintu gerbang terakhir merangkumi p99 permintaan, p99 dan maksima jeda, jumlah nisbah jeda, kadar peruntukan, old-after-GC, rantau humongous, daya pemprosesan, CPU, RSS, ralat, dan OOM. Hanya selepas itu saya akan meningkatkan trafik, dengan keupayaan undur balik dikekalkan."
Kesilapan Biasa
- **Kesilapan: mengisytiharkan GC sebagai punca selepas melihat graf timbunan gigi gergaji → Mengapa ia gagal: graf membuktikan
pengutipan berlaku, bukan bahawa lonjakan permintaan dan jeda hentikan-dunia bertindih pada satu tika → Pembetulan: korelasikan permintaan, log, dan JFR dengan tika, ID GC, dan satu garis masa.**
- **Kesilapan: hanya melihat pada purata tempoh GC → Mengapa ia gagal: purata menyembunyikan satu peristiwa ekor
tiga saat dan mengabaikan jumlah kos bagi banyak jeda pendek → Pembetulan: ukur persentil jeda, maksima, masa dijeda seminit, dan sebab.**
- **Kesilapan: menganggap tempoh kitaran GC sebagai tempoh jeda aplikasi → Mengapa ia gagal: kebanyakan kerja penandaan
G1 boleh berjalan serentak dengan aplikasi → Pembetulan: gunakan peristiwa jeda sebenar dan SLI permintaan.**
- **Kesilapan: meningkatkan timbunan daripada 12 GiB kepada 24 GiB semasa insiden → Mengapa ia gagal: ini mungkin menyembunyikan
pengekalan tanpa batas dan meningkatkan risiko memori tanpa membuktikan bahawa set hidup mempunyai had yang sah → Pembetulan: pisahkan kadar peruntukan daripada pertumbuhan set hidup pasca-pengutipan, kemudian jalankan eksperimen kapasiti yang boleh diterbalikkan.**
- **Kesilapan: mengambil lambakan timbunan serta-merta pada satu-satunya tika pengeluaran → Mengapa ia gagal: arahan
tersebut berimpak tinggi, mungkin meminta Full GC secara lalai, menulis fail yang besar, dan mendedahkan data sensitif → Pembetulan: alirkan keluar trafik dan kumpulkannya pada replika atau main semula terkawal.**
- **Kesilapan: mengubah saiz rantau G1 selepas menyedari adanya objek besar → Mengapa ia gagal: objek besar mungkin tidak
melebihi ambang separuh rantau, dan bendera tersebut mengubah granulariti rantau merentas timbunan → Pembetulan: sahkan objek humongous dengan gc+heap dan bukti peruntukan, kemudian bandingkan eksperimen.**
- **Kesilapan: menganggap
-XX:MaxGCPauseMillis=50sebagai SLA → Mengapa ia gagal: ia ialah petunjuk matlamat dan G1 bukanlah
pengutip masa nyata (real-time collector) → Pembetulan: sahkan taburan jeda sebenar dan belanjawankan pertukaran (tradeoff) antara sasaran, daya pemprosesan, dan ruang legar timbunan.**
- **Kesilapan: menyahdayakan GC eksplisit secara global sebaik sahaja
System.gc()muncul → Mengapa ia gagal: kebergantungan
atau aliran kerja operasi mungkin bergantung pada semantik tersebut → Pembetulan: kenal pasti pemanggil dan niat sebelum mengalih keluar, mengkonfigurasi, atau mengasingkannya.**
- **Kesilapan: hanya memeriksa bahawa p99 menurun selepas menukar pengutip → Mengapa ia gagal: jeda yang lebih rendah mungkin
datang dengan CPU yang lebih tinggi, daya pemprosesan yang lebih rendah, atau lebih banyak memori → Pembetulan: uji kependaman, daya pemprosesan, CPU, RSS, ralat, dan pemulihan di bawah beban yang sama.**
Soalan Susulan dan Maklum Balas
Susulan 1: Bagaimanakah anda membezakan kebocoran memori daripada pemanasan cache biasa?
Periksa set hidup selepas beberapa pengutipan lama pada beban yang setanding, bukan hanya kecerunan awal selepas proses dimulakan. Cache terhad yang normal mendatar selepas mencapai berat maksimum dan kadar kenaan yang stabil, serta penyingkiran (eviction) dan penamatan tempoh TTL sepatutnya boleh diperhatikan. Kebocoran membiarkan objek tanpa nilai perniagaan kekal boleh dicapai daripada punca GC, jadi garis dasar terus meningkat. Gunakan histogram kelas dari beberapa masa untuk mencari kelas yang berkembang, kemudian periksa dominator, saiz tertahan, dan laluan rujukan dalam lambakan timbunan terkawal. Walaupun cache akhirnya mendatar, platform 9.2 GiB dalam timbunan 12 GiB mungkin meninggalkan ruang legar yang tidak mencukupi untuk penandaan serentak dan lonjakan mendadak (bursts), menjadikannya masalah reka bentuk kapasiti.
Susulan 2: Mengapa tidak mengurangkan MaxGCPauseMillis terlebih dahulu?
Ia membimbing berapa banyak kerja yang dicuba oleh G1 bagi setiap pengutipan; ia bukan batas atas yang dikuatkuasakan. Jika set hidup terlalu besar, penandaan serentak ketinggalan, atau kontena tidak dapat membekalkan CPU, sasaran yang lebih rendah mungkin menyebabkan setiap pengutipan bercampur menebus lebih sedikit, meningkatkan kekerapan, dan menggerakkan proses lebih dekat kepada kegagalan pemindahan. Mula-mula bentuk hipotesis daripada pemasaan fasa, ruang legar timbunan, dan kadar peruntukan atau promosi, kemudian sahkan satu perubahan bendera di bawah beban yang sama.
Susulan 3: Apakah yang dicadangkan oleh masa nyata yang panjang tetapi masa pengguna dan sistem yang pendek dalam log GC?
Ia mencadangkan bahawa urutan GC tidak menggunakan CPU sepanjang keseluruhan selang jam dinding (wall-clock interval). Calon yang berpotensi termasuk pendikit CPU kontena, perebutan hos, swap atau ralat halaman utama (major page faults), jeda pemayaan (virtualization pauses), dan I/O log. Periksa kuota cgroup dan masa dipenditkan, giliran larian (run queue), ralat halaman, swap, kependaman cakera, dan peristiwa hos yang diletakkan bersama (colocated-host). Menambah urutan GC selari boleh meningkatkan perebutan; tangani bukti bekalan sumber luaran terlebih dahulu.
Susulan 4: Bilakah anda akan mempertimbangkan untuk beralih daripada G1 kepada ZGC?
Pertimbangkannya apabila perkhidmatan mempunyai matlamat kependaman rendah yang eksplisit, peruntukan dan pertumbuhan set hidup berada di bawah kawalan, G1 masih terlepas SLO jeda pada timbunan dan beban sasaran, dan pasukan boleh mengesahkan keperluan CPU tambahan, ruang legar timbunan, keserasian JDK, dan operasi. Jalankan ujian A/B dengan trafik berbentuk pengeluaran, termasuk permulaan sejuk, keadaan stabil, lonjakan mendadak, pemulihan kegagalan, dan had kontena. Migrasi pengutip ialah pilihan kapasiti dan model masa larian; ia tidak menggantikan usaha membaiki kebocoran objek atau cache tanpa had.
Susulan 5: Bagaimanakah anda membuktikan pembaikan itu bertahan dan bukannya sekadar melambatkan lonjakan?
Jalankan kenari cukup lama untuk merangkumi beberapa kitaran lonjakan asal, keadaan stabil cache, dan puncak yang dijangkakan. Bandingkan kecerunan old-after-GC, Full GC setiap jam dan kegagalan pemindahan, kadar peruntukan, rantau humongous, jumlah nisbah jeda, dan SLI permintaan, serta uji melangkaui puncak yang diramalkan untuk memeriksa ruang legar. Jika timbunan yang lebih besar hanya menganjakkan lonjakan pertama daripada lima minit kepada sepuluh manakala kecerunan garis dasar tidak berubah, langkah pemulihan telah gagal.