Ders 15 / 17
Bellek Sızıntısı Tanısı
Sızıntının istenmeyen erişilebilirlik olarak tanımı, eşzamansız kodda dört yaygın kaynak, öbek anlık görüntüsünün içeriği ve iki görüntüyü karşılaştırarak birikimi sayma yöntemi.
İçindekiler
Toplayıcı erişilemeyen her nesneyi toplar. O halde bellek neden dolar? Yanıt tanımın kendisindedir: toplanmayan nesneler erişilebilir nesnelerdir. Sızıntı, toplayıcının kaçırdığı bellek değil, programın farkında olmadan tuttuğu bellektir.
Bu ders sızıntıyı ölçülebilir hale getirir. Önce eşzamansız kodda en sık görülen dört kaynak tanınır, sonra öbek anlık görüntüsüyle birikim sayılır. Ölçüm akışının sızdıran ve sınırlı iki sürümü aynı ölçütle karşılaştırılacak.
Sızıntının Tanımı
Bellek sızıntısı, artık kullanılmayacak bir nesnenin köklerden erişilebilir kalmasıdır. Tanımda iki parça vardır ve ikisi de gereklidir: nesne gereksizdir ve erişilebilirdir.
Bu tanım, sızıntı avını somut bir soruya indirger: bu nesneye hangi başvuru zinciri üzerinden ulaşılıyor? Zincir bulunduğunda düzeltme de bellidir; zinciri kıran satır yazılır.
Bir uyarı gerekir: artan bellek her zaman sızıntı değildir. Önbellek dolarken bellek artar ve bu tasarımın gereğidir. Ayırt edici ölçüt, artışın durup durmadığıdır. Sınırlı bir yapı bir noktada dengelenir; sızıntı doğrusal artmayı sürdürür.
Eşzamansız Kodda Dört Kaynak
Sınırsız birikim. Her sonucu bir diziye ya da haritaya ekleyen ve hiç çıkarmayan kod. Ölçüm akışında en sık görülen biçimdir: “geçmişi tutalım” ile başlar, sınır konmadığı için sürer.
Kaldırılmayan dinleyici. Bir olay kaynağına eklenen ve hiç kaldırılmayan dinleyici, kapattığı her şeyi kaynak yaşadığı sürece tutar. Aynı bileşen defalarca kaydolursa dinleyici sayısı da doğrusal artar; çalışma zamanları belirli bir sayıdan sonra uyarı verir.
İptal edilmeyen zamanlayıcı. Bekleyen bir zamanlayıcı köktür; geri çağrısının kapattığı her değer bellekte kalır. Kendi kendini zamanlayan bir akış, durdurulmadıkça bunu süresiz sürdürür.
Sonuçlanmayan söz. Beklemede kalan bir söz, kendisine bağlanmış geri çağrıları ve onların kapattığı değerleri tutar.
Son kaynak en az görünen olduğu için gösterilmeye değer.
const kayitDefteri = new FinalizationRegistry((ad) => { console.log("toplandı:", ad); }); function bekleyenIs() { const tampon = { ad: "ölçüm tamponu" }; kayitDefteri.register(tampon, "sonuçlanmayan sözün tuttuğu tampon"); const soz = new Promise(() => { // Bu söz hiçbir zaman sonuçlanmaz. }); soz.then(() => console.log("işlendi:", tampon.ad)); return soz; } let bekleyen = bekleyenIs(); global.gc(); await new Promise((karar) => setTimeout(karar, 10)); global.gc(); console.log("söze başvuru sürerken toplama turu bitti"); bekleyen = null; global.gc(); await new Promise((karar) => setTimeout(karar, 10)); global.gc(); await new Promise((karar) => setTimeout(karar, 10)); console.log("başvuru bırakıldıktan sonraki tur bitti");
$ node --expose-gc bekleyen.mjs söze başvuru sürerken toplama turu bitti toplandı: sonuçlanmayan sözün tuttuğu tampon başvuru bırakıldıktan sonraki tur bitti
Başvuru zinciri şudur: modül değişkeni → beklemede söz → kayıtlı tepki → geri çağrının kapanışı → tampon. Zincirin ilk halkası bırakıldığında tamamı toplandı.
Buradan çıkan pratik kural, iptal ve zaman aşımı dersini bellek tarafından tekrar gerekçelendirir: her bekleyişin sonlanma güvencesi olmalıdır. Zaman aşımı yalnız bir kullanıcı deneyimi kararı değil, bir bellek kararıdır.
Öbek Anlık Görüntüsü
Öbek anlık görüntüsü (heap snapshot), belirli bir andaki nesne çizgesinin kaydıdır: düğümler nesnelerdir, kenarlar başvurulardır. Her düğüm için tip, ad ve boyut bilgisi tutulur.
Görüntüde iki büyüklük ayrı ayrı okunur. Sığ boyut, nesnenin kendi kapladığı yerdir. Tutulan boyut, nesne toplandığında geri kazanılacak toplam yerdir — yani yalnız o nesne üzerinden erişilebilen her şeyin toplamı. Sızıntı avında anlamlı olan ikincisidir: küçük bir nesne, büyük bir yapıyı tutuyor olabilir.
Görüntü, çalışma zamanının hata ayıklama arayüzünden alınır. Program içinden de alınabilir; aşağıdaki işlev bunu yapar ve belirli bir sınıfın kaç örneğinin yaşadığını sayar.
İki Görüntüyü Karşılaştırmak
Tek bir görüntü “çok nesne var” der; sızıntıyı göstermez. Yöntem, aynı işi tekrarlayıp görüntüleri karşılaştırmaktır:
- İşlem başlamadan bir görüntü alınır — taban çizgisi.
- İşlem birçok kez tekrarlanır.
- İkinci görüntü alınır ve fark incelenir.
Beklenti, işlemin ürettiği geçici nesnelerin ikinci görüntüde bulunmamasıdır. Bulunuyorsa ve sayıları tekrar sayısıyla orantılıysa, birikim vardır.
import { Session } from "node:inspector/promises"; class Olcum { constructor(istasyon, deger) { this.istasyon = istasyon; this.deger = deger; } } async function ornekSayisi(sinifAdi) { const oturum = new Session(); oturum.connect(); const parcalar = []; oturum.on("HeapProfiler.addHeapSnapshotChunk", (ileti) => parcalar.push(ileti.params.chunk)); await oturum.post("HeapProfiler.takeHeapSnapshot", { reportProgress: false }); oturum.disconnect(); const anlik = JSON.parse(parcalar.join("")); const alanlar = anlik.snapshot.meta.node_fields; const tipDizini = alanlar.indexOf("type"); const adDizini = alanlar.indexOf("name"); const nesneTipi = anlik.snapshot.meta.node_types[tipDizini].indexOf("object"); let sayi = 0; for (let i = 0; i < anlik.nodes.length; i += alanlar.length) { const tip = anlik.nodes[i + tipDizini]; const ad = anlik.strings[anlik.nodes[i + adDizini]]; if (tip === nesneTipi && ad === sinifAdi) sayi += 1; } return sayi; } const gecmis = []; function sizdiranIsle(olcum) { gecmis.push(olcum); } const pencere = []; function sinirliIsle(olcum) { pencere.push(olcum); if (pencere.length > 10) pencere.shift(); } console.log("1. anlık görüntü — Olcum örneği:", await ornekSayisi("Olcum")); for (let i = 0; i < 500; i += 1) sizdiranIsle(new Olcum("A1", 21.4)); console.log("2. anlık görüntü — sızdıran işleyiciden sonra:", await ornekSayisi("Olcum")); gecmis.length = 0; for (let i = 0; i < 500; i += 1) sinirliIsle(new Olcum("A1", 21.4)); console.log("3. anlık görüntü — sınırlı işleyiciden sonra:", await ornekSayisi("Olcum"));
1. anlık görüntü — Olcum örneği: 0 2. anlık görüntü — sızdıran işleyiciden sonra: 500 3. anlık görüntü — sınırlı işleyiciden sonra: 10
Sayılar tanıyı doğrudan verir. Beş yüz ölçüm işlendi; sızdıran işleyiciden sonra beş yüzünün beş yüzü de bellekte. Sınırlı işleyicide ise pencere boyu kadar — on — nesne kaldı, geri kalanı toplandı.
Ölçütün gücü, oranın kendisindedir: örnek sayısı işlem sayısıyla orantılı artıyorsa sızıntı kesindir. Sabit bir üst sınırda duruyorsa yapı sınırlıdır.
Anlık görüntü almanın kendisi de bir çöp toplama turu tetikler; bu nedenle sayımda yalnız gerçekten erişilebilir olan nesneler görünür. Sayının kararlı çıkmasının nedeni budur.
Tanıdan Düzeltmeye
Sayım, hangi sınıfın biriktiğini söyler; başvuru zincirini söylemez. Arayüz tabanlı araçlarda zincir, “tutan yol” görünümüyle doğrudan okunur. Program içinden yapılan bir sayımda ise zincir, kodun kendisinden çıkarılır: nesneyi hangi yapı tutuyor, o yapı neden büyüyor.
Düzeltme üç kalıptan birine indirgenir. Sınır koymak — pencere, kapasiteli önbellek, en eski girdiyi düşüren politika. Bağı kaldırmak — dinleyiciyi kaldırmak, zamanlayıcıyı iptal etmek, isteği durdurmak. Zayıf başvuruya geçmek — eşlemenin ömrü anahtar nesnenin ömrüne bağlıysa.
Özet
- Sızıntı, gereksiz bir nesnenin köklerden erişilebilir kalmasıdır; toplayıcı kusuru değil program kusurudur.
- Eşzamansız kodda dört yaygın kaynak vardır: sınırsız birikim, kaldırılmayan dinleyici, iptal edilmeyen zamanlayıcı ve sonuçlanmayan söz.
- Öbek anlık görüntüsü nesne çizgesinin kaydıdır; sızıntı avında tutulan boyut sığ boyuttan daha bilgilendiricidir.
- Tanı tek görüntüyle değil, aynı işlemin tekrarından önce ve sonra alınan iki görüntünün karşılaştırılmasıyla konur.
- Örnek sayısı tekrar sayısıyla orantılı artıyorsa sızıntı vardır; sabit bir sınırda duruyorsa yapı sınırlıdır.
Sonraki Adım
Bellek tarafı tamamlandı. Geriye zaman tarafı kalıyor: bir program bellek sızdırmadan da yavaş olabilir. Sonraki ders ana iş parçacığının zaman çizelgesini okur — uzun görevin tanımı, olay döngüsü gecikmesinin ne anlama geldiği, örnekleyici profilcinin ne kaydettiği ve uzun bir işi bölerek araya sıra vermenin gözlenebilir etkisi.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.