---
title: 'Çöp Toplama'
source: 'https://academia.sh/tr/kurslar/eszamansiz-javascript/cop-toplama'
course: 'Eşzamansız JavaScript ve Çalışma Zamanı'
language: tr
updated: '2026-08-17T18:09:44+00:00'
license: 'CC BY-SA 4.0'
---

# Çöp Toplama

Erişilebilirlik temelli toplamanın işleyişi, başvuru saymanın çevrimlerde başarısız oluşu, kuşak varsayımı, artımlı toplamanın duraklamaları ve zayıf başvuru yapıları.

Önceki ders toplayıcıyı kara kutu olarak kullandı: "erişilemeyeni toplar" denildi. Bu
ders kutuyu açar. Amaç toplayıcı yazmak değil, davranışını öngörebilmektir — özellikle
duraklamaların nereden geldiğini ve zayıf başvuruların hangi boşluğu doldurduğunu.

## İşaretle ve Süpür

Temel yöntem iki aşamalıdır. **İşaretleme** aşamasında kök kümesinden başlanır ve
başvurular izlenerek ulaşılan her nesne işaretlenir. **Süpürme** aşamasında işaretlenmemiş
nesnelerin yeri geri alınır.

Bu, Veri Yapıları kursundaki çizge dolaşımının doğrudan uygulanmasıdır: nesneler düğüm,
başvurular kenardır; işaretleme, köklerden başlayan bir erişilebilirlik dolaşımıdır.
Ziyaret işaretlemesi de aynı işi görür — daha önce görülen nesne yeniden dolaşılmaz.

Yöntemin belirleyici özelliği şudur: maliyeti ölü nesne sayısına değil, **yaşayan nesne
sayısına** bağlıdır. Ölü nesneler hiç ziyaret edilmez; yalnız yerleri geri alınır.

## Başvuru Sayma Neden Yetmez

Alternatif bir yöntem, her nesnede kendisine kaç başvuru olduğunu saymaktır. Sayı sıfıra
düştüğünde nesne serbest bırakılır. Bu yöntem hızlıdır ve duraklama üretmez; ama bir
sınıfı hiç toplayamaz: birbirine başvuran nesneler.

```js
const toplananlar = [];
const kayitDefteri = new FinalizationRegistry((ad) => {
  toplananlar.push(ad);
});

function cevrimKur() {
  const a = { ad: "A1 düğümü" };
  const b = { ad: "B2 düğümü" };
  a.komsu = b;
  b.komsu = a;
  kayitDefteri.register(a, "çevrimdeki A1");
  kayitDefteri.register(b, "çevrimdeki B2");
  console.log("çevrim kuruldu:", a.komsu.ad, "<->", b.komsu.ad);
}

cevrimKur();

global.gc();
await new Promise((karar) => setTimeout(karar, 10));
global.gc();
await new Promise((karar) => setTimeout(karar, 10));
console.log("toplananlar:", toplananlar.sort().join(", "));
```

```
$ node --expose-gc cevrim.mjs
çevrim kuruldu: B2 düğümü <-> A1 düğümü
toplananlar: çevrimdeki A1, çevrimdeki B2
```

Toplama sırası öngörülemez olduğu için adlar biriktirilip sıralanarak yazdırıldı; bu, bir
sonraki dersteki uyarının erken bir örneğidir — toplayıcının **hangi** nesneyi topladığı
gözlenebilir, **hangi sırayla** topladığı gözleme dayandırılamaz.

İki nesnenin her birine bir başvuru vardı ve bu başvurular hiç sıfırlanmadı; buna karşın
ikisi de toplandı. Nedeni açıktır: kök kümesinden hiçbirine ulaşılamıyordu. Erişilebilirlik
ölçütü, "kaç başvuru var" sorusunu değil "köklerden ulaşılıyor mu" sorusunu sorar ve
çevrimler bu soruyu doğru yanıtlar.

Ayrım pratikte sık karşılaşılan bir yapı için önemlidir: birbirine başvuran iki nesne —
üst ve alt öğe, gözlemci ve gözlenen, iki uçlu bir liste düğümü — JavaScript'te sızıntı
kaynağı değildir. Sızıntı, çevrimden değil kökten gelir.

## Kuşak Varsayımı

Ölçümler tutarlı bir gözlem verir: **nesnelerin çoğu kısa yaşar.** Bir fonksiyonun içinde
üretilen ara nesneler hemen ölür; uygulama boyunca yaşayan yapılar ise azdır.

Toplayıcılar bu gözlemi kullanır. Öbek en az iki bölgeye ayrılır: yeni nesnelerin
ayrıldığı genç bölge ve toplamayı atlatan nesnelerin taşındığı yaşlı bölge. Genç bölge
sık ve hızlı taranır; yaşlı bölge seyrek taranır.

Sonucu, sık yapılan bir mikro eniyilemenin gereksizliğidir: kısa ömürlü nesne üretmekten
kaçınmak çoğu durumda kazanç getirmez, çünkü toplayıcı zaten bu duruma göre
ayarlanmıştır. Asıl maliyet, yaşlı bölgeye geçen ve orada gereksiz yere kalan nesnelerdir.

## Duraklamalar

İşaretleme sırasında nesne çizgesi değişmemelidir; aksi halde işaretleme tutarsız olur.
Bu nedenle toplayıcı çalışırken program durur — tek iş parçacıklı bir ortamda bunun
anlamı, olay döngüsünün de durmasıdır.

Duraklamayı küçültmek için iki teknik kullanılır. **Artımlı toplama**, işaretlemeyi küçük
parçalara böler ve aralarında programa sıra verir. **Eşzamanlı toplama**, işaretlemenin
bir bölümünü ayrı bir iş parçacığında yürütür. İkisi birlikte, uzun tek bir duraklamayı
çok sayıda kısa duraklamaya dönüştürür.

Uygulama açısından çıkarım şudur: çöp toplama bir başarım kalemidir ve ana iş parçacığında
görünür. Bir sonraki dersteki tanı yöntemleri ve profilleme, toplama duraklamalarını da
kapsar.

## Zayıf Başvurular

Bazı durumlarda bir nesneye başvurmak ama onu **yaşatmamak** istenir: bir önbellek, bir
kimlik eşlemesi, bir gözlemci kaydı. Güçlü başvuru bu iş için yanlıştır; nesne artık
kullanılmasa bile önbellekte durduğu için toplanamaz.

Zayıf yapılar bu boşluğu doldurur. `WeakMap` ve `WeakSet`, anahtarlarını yaşatmaz.

```js
const kayitDefteri = new FinalizationRegistry((ad) => {
  console.log("toplandı:", ad);
});

const gucluHarita = new Map();
const zayifHarita = new WeakMap();

function gucluTut() {
  const anahtar = { istasyon: "A1" };
  gucluHarita.set(anahtar, "güçlü haritadaki değer");
  kayitDefteri.register(anahtar, "güçlü haritanın anahtarı");
}

function zayifTut() {
  const anahtar = { istasyon: "B2" };
  zayifHarita.set(anahtar, "zayıf haritadaki değer");
  kayitDefteri.register(anahtar, "zayıf haritanın anahtarı");
}

gucluTut();
zayifTut();

global.gc();
await new Promise((karar) => setTimeout(karar, 10));
global.gc();
await new Promise((karar) => setTimeout(karar, 10));

console.log("güçlü haritadaki giriş sayısı:", gucluHarita.size);
console.log("toplama turu bitti");
```

```
$ node --expose-gc zayif.mjs
toplandı: zayıf haritanın anahtarı
güçlü haritadaki giriş sayısı: 1
toplama turu bitti
```

İki anahtar da fonksiyonlar döndükten sonra erişilemez hale geldi. Zayıf haritadaki
anahtar toplandı; güçlü haritadaki anahtar toplanmadı, çünkü haritanın kendisi ona güçlü
bir başvuru tutuyordu ve harita da köklerden erişilebilirdi.

Buradan çıkan kural doğrudandır: **bir eşlemenin ömrü anahtar nesnenin ömrüne bağlıysa
zayıf yapı kullanılır.** Ölçüm akışında istasyon nesnesi başına tutulan yardımcı veri
buna örnektir; istasyon nesnesi düştüğünde yardımcı veri de düşmelidir.

Zayıf yapıların üç sınırı vardır. Anahtarları yalnız nesne olabilir. Üzerlerinde gezinme
yapılamaz, boyutları sorulamaz — çünkü içerik toplayıcının kararına bağlı olarak değişir
ve bu gözlemlenebilir olsaydı program belirlenimci olmazdı. `WeakRef` ile tekil bir zayıf
başvuru da tutulabilir; ancak `deref` çağrısının ne zaman boş döneceği öngörülemez, bu
yüzden program mantığı buna dayandırılmaz.

## Kuşak Varsayımını Ölçmek

Kuşak varsayımının doğrudan gözlenebilir bir izi vardır: kısa ömürlü nesnelerden oluşan bir
döngü, yığın kullanımını kalıcı olarak büyütmez. Ölçüm mutlak sayılarla yapılamaz — değerler
çalıştırmaya, sürüme ve makineye göre değişir — ama **ilişki** sınanabilir.

```js
function yigin() {
  const b = process.memoryUsage();
  return { heapUsed: Math.round(b.heapUsed / 1024) };
}

const once = yigin();

for (let i = 0; i < 200000; i++) {
  const gecici = { sensor: "S-01", deger: i };
  if (gecici.deger < 0) console.log("olmaz");
}

const sonra = yigin();
global.gc();
const toplamaSonrasi = yigin();

console.log("kısa ömürlü döngü öncesi (KiB):", once.heapUsed > 0);
console.log("toplama sonrası yığın, döngü sonrasından küçük mü:",
            toplamaSonrasi.heapUsed <= sonra.heapUsed);
```

```
$ node --expose-gc kusak.mjs
kısa ömürlü döngü öncesi (KiB): true
toplama sonrası yığın, döngü sonrasından küçük mü: true
```

İki yüz bin nesne yaratıldı ve hiçbiri döngüden sonra erişilebilir değil. Toplama
çağrıldığında yığın kullanımı geri düşer; genç kuşakta ölen nesneler için ödenen bedel,
yaşayanların kopyalanmasıyla sınırlıdır.

Sayı yerine karşılaştırma yazdırmak bilinçlidir: mutlak bayt değerleri her çalıştırmada
farklıdır ve derse yazıldığında yanıltıcı olur. Ölçülebilir olan, kullanımın yönüdür.

## Toplayıcının Vaat Etmedikleri

Üç noktanın açıkça bilinmesi gerekir.

Toplama anı öngörülemez. "Erişilemez oldu" ile "bellek geri verildi" arasındaki süre
çalışma zamanının kararıdır.

Sonlandırıcı geri çağrılar güvence değildir. Program sonlanırken hiç çalışmayabilir; bu
nedenle dosya, bağlantı ve zamanlayıcı gibi kaynakların temizliği açık çağrılarla yapılır.

Toplayıcı sızıntıyı çözmez. Erişilebilir bir nesne, gereksiz olsa bile toplanmaz. Sızıntı
bir toplayıcı kusuru değil, bir program kusurudur — ve bu nedenle tanısı programda aranır.

## Özet

- İşaretle-süpür yöntemi köklerden başlayan bir erişilebilirlik dolaşımıdır; maliyeti
  yaşayan nesne sayısına bağlıdır.
- Başvuru sayma çevrimleri toplayamaz; erişilebilirlik ölçütü toplar, bu yüzden karşılıklı
  başvuran nesneler JavaScript'te sızıntı kaynağı değildir.
- Kuşak varsayımı, nesnelerin çoğunun kısa yaşadığı gözlemine dayanır ve genç bölgenin sık
  taranmasını sağlar.
- Toplama ana iş parçacığını durdurur; artımlı ve eşzamanlı teknikler uzun duraklamayı
  kısa duraklamalara böler.
- Zayıf yapılar anahtarlarını yaşatmaz; ömrü başka bir nesnenin ömrüne bağlı eşlemeler
  için kullanılır.

## Sonraki Adım

Toplayıcının nasıl çalıştığı bilindiğine göre, çalışmadığı durumlar tanınabilir hale
gelir. Sonraki ders sızıntıyı tanımlar ve ölçer: eşzamansız kodda en sık görülen dört
sızıntı biçimi, öbek anlık görüntüsünün ne içerdiği ve iki anlık görüntüyü karşılaştırarak
hangi nesnelerin biriktiğini sayma yöntemi. Ölçüm akışının sızdıran ve sızdırmayan iki
sürümü aynı ölçütle karşılaştırılacak.
