---
title: 'Bellek Kullanımı'
source: 'https://academia.sh/tr/kurslar/python-eszamanlilik/bellek-kullanimi'
course: 'Eşzamanlılık ve Başarım'
language: tr
updated: '2026-08-17T18:10:24+00:00'
license: 'CC BY-SA 4.0'
---

# Bellek Kullanımı

Aynı 80 adım altı biçimde tutulduğunda ayakta duran nesne sayısı 1 ile 172 arasında değişir; paylaşılan dizgi 11, ayrı dizgi 89, sözlüklü nesne 172, yuvalı nesne 91 nesne tutar ve altısı da çizelgeleyiciye aynı 31 tik / 49 örtüşen adımı verir.

Önceki ders bir koşumun çağrı dökümünü açtı ve sıcak yolu çağrı sayısıyla buldu. Dökümün
söylemediği bir şey vardı: `ilerlet` her iki yükte de 80 kez çağrıldı, ama o 80 çağrının
üzerinde çalıştığı yapı bellekte **kaç nesne** olarak duruyordu?

Soru boşuna değil. Sekiz görevin on adımı, bir liste içinde liste olarak da tutulabilir, her
adımı bir nesne yapan bir sınıfla da, tek bir bayt dizisiyle de. Üçü de aynı 80 adımı
taşır ve çizelgeleyiciye aynı yanıtı verdirir. Ayakta tuttukları nesne sayısı ise aynı
değildir — ve bu ders o sayıyı ölçer.

## Neden Bayt Değil Nesne

Bir yapının bellekte kapladığı yeri bayt olarak sormak doğal görünür, ama o sayı bu kursun
ölçüsü değildir. Nedeni ölçünün kendisindedir: bir nesnenin bayt karşılığı yorumlayıcının
nesneyi nasıl yerleştirdiğine bağlıdır ve ortamdan ortama değişir. Değişen bir sayı iki
biçimi karşılaştıramaz.

Nesne sayısı ise yapının kendisinden gelir. Bir listede kaç öğe olduğu, kaç öğenin aynı
nesneyi gösterdiği, bir örneğin ayrıca bir sözlük taşıyıp taşımadığı — bunların hepsi
gezilerek sayılabilir ve her koşumda aynı çıkar.

Sayımın bir sınırı olmak zorunda. Bir nesneden başlayıp erişilebilen her şeyi gezmek,
tipine, tipin tanımlandığı modüle ve oradan da programın tamamına ulaşır; böyle bir sayı
yapıyı değil ortamı ölçer. Bu yüzden gezme kapları izler — liste, demet, sözlük, örnek
sözlüğü ve yuva — ve tip nesnelerinde, işlevlerde, modüllerde durur. Sayılan şey **verinin
tuttuğu yapıdır**, o veriyi kullanan programın tamamı değil.

Sayının anlamı da vardır. Her nesnenin kendi **kimliği**, kendi tipi ve kendi yaşam süresi
vardır; bunları taşımak nesne başına sabit bir yük getirir ve bu yük nesnenin içindeki
veriyle orantılı değildir. On adımlık bir listeyi seksen ayrı nesneye dağıtmak, veriyi
büyütmeden yükü seksen kez ödemek demektir. **Bellek iddiası bu yüzden nesne sayısıyla
kurulur.**

## Var Etmekle Ayakta Tutmak

Veri Yapıları ve Fonksiyonel Araçlar kursu **var edilen** nesneyi saydı: her üretimini kendi
sayan bir sınıfla, bir biçimin koşum boyunca kaç nesne ürettiği ölçüldü ve tembel biçimin
üretimi azaltmadığı, yalnız tutmayı azalttığı gösterildi. **Bu ölçüm burada tekrarlanmaz**,
atıfla kullanılır.

Buradaki soru öbür yarısıdır: koşum bittikten sonra, elde tutulan yapının içinde **aynı anda
kaç nesne ayakta duruyor?** Var etme bir akış ölçüsüdür, ayakta durma bir durum ölçüsü. İki
biçim aynı sayıda nesne var edip bambaşka sayıda nesne tutabilir; iki biçim aynı sayıda
nesne tutup bambaşka sayıda nesne var etmiş olabilir.

## Altı Biçim

Ölçülen yapılar, ortak tanımın ürettiği sekiz görevden türetilir ve hepsi aynı 80 adımı
taşır.

**Liste, paylaşılan dizgi** ortak tanımın kendi biçimidir: adımlar iki değişmez dizgiyi
gösterir ve 80 yuvanın hepsi bu iki nesneden birine bağlanır. **Liste, ayrı dizgi** aynı
yapıdır, tek farkı her adımın dizgisinin çalışma anında yeniden kurulmasıdır — değerler
eşittir, nesneler ayrıdır. **Sözlük, paylaşılan dizgi** dış listeyi görev numarasıyla
anahtarlanmış bir sözlüğe çevirir.

**Nesne, sözlüklü** her adımı bir sınıf örneğine sarar; örnek, niteliklerini bir sözlükte
tutar. **Nesne, yuvalı** aynı sınıfı `__slots__` bildirimiyle kurar; nitelik adları önceden
sabitlendiği için örnek ayrıca sözlük taşımaz. **Tek bayt dizisi** 80 adımı tek bir
değişmez bayt dizisinde toplar; görev sınırları aritmetikle geri kazanılır.

Ölçümün varsayımları:

- **BS7** — Altı biçim de ortak tanımın `gorevler` çıktısından türetilir ve aynı 80 adımı
  taşır; hiçbiri veriyi değiştirmez.
- **BS8** — Sayım yapıyı gezer ve **ayrı** nesneleri sayar: paylaşılan bir nesne kaç yerden
  gösterilirse gösterilsin **bir** sayılır. Ayırt etme kimlik üzerinden yapılır ama
  **hiçbir kimlik sayısı basılmaz.**
- **BS9** — Gezme listeleri, demetleri, sözlükleri, örnek sözlüklerini ve yuvaları izler.
  Tip nesneleri, işlevler ve modüller sayılmaz; sayılan şey **yapının kendisidir**, koşumun
  tamamı değil.
- **BS10** — Ölçülen şey **ayakta duran** nesnedir. Yapı kurulurken oluşan ara nesneler
  sayıma girmez; onlar Veri Yapıları kursunun ölçüsüdür.
- **BS11** — Ölçülen bayt **yazılmaz**. Bir yapının bayt karşılığı ortama bağlıdır; nesne
  sayısı bağlı değildir ve iki biçimi karşılaştıran sayı budur.
- **BS12** — Her biçim çizelgeleyiciye verilmeden önce ortak dizime çözülür ve çözülen
  dizinin ortak tanımınkiyle aynı olup olmadığı tabloda gösterilir; aynı değilse
  karşılaştırma geçersizdir.

## Ölçüm

```python
"""Bellek: ayni 80 adim alti bicimde; sayilan bayt degil, ayakta duran nesne."""

TOHUM = 20260817
ISLEMCI, GC = "islemci", "g_c"


def uretec(tohum):
    d = tohum % 2147483646 + 1

    def r(n):
        nonlocal d
        d = (d * 48271) % 2147483647
        return d % n
    return r


def gorevler(sayi=8, adim=10, gc_payi=7, tohum=TOHUM):
    r, liste = uretec(tohum), []
    for i in range(sayi):
        liste.append([GC if r(10) < gc_payi else ISLEMCI for _ in range(adim)])
    return liste


def kosum(gorevler, isci, islemci_yuvasi):
    kalan = [list(g) for g in gorevler]
    tik = ortusen = islemci_adim = gc_adim = 0
    while any(kalan):
        etkin = [i for i, g in enumerate(kalan) if g][:isci]
        if not etkin:
            break
        yuva, ilerleyen = islemci_yuvasi, 0
        for i in etkin:
            adim = kalan[i][0]
            if adim == ISLEMCI:
                if yuva <= 0:
                    continue
                yuva -= 1
                islemci_adim += 1
            else:
                gc_adim += 1
            kalan[i].pop(0)
            ilerleyen += 1
        tik += 1
        ortusen += max(0, ilerleyen - 1)
    return tik, ortusen, islemci_adim, gc_adim


def cocuklar(n):
    if isinstance(n, (list, tuple)):
        return list(n)
    if isinstance(n, dict):
        return list(n.keys()) + list(n.values())
    if hasattr(n, "__dict__"):
        return [n.__dict__]
    if hasattr(type(n), "__slots__"):
        return [getattr(n, a) for a in type(n).__slots__]
    return []


def nesneleri_say(kok):
    """Yapiyi gezer; paylasilan nesne bir kez sayilir. Kimlik basilmaz."""
    gorulen, tutulan, yigin, tur = set(), [], [kok], {}
    while yigin:
        n = yigin.pop()
        if id(n) in gorulen:
            continue
        gorulen.add(id(n))
        tutulan.append(n)
        ad = type(n).__name__
        tur[ad] = tur.get(ad, 0) + 1
        yigin.extend(cocuklar(n))
    return len(gorulen), tur


def ayri_dizgi(s):
    return "".join([s[:2], s[2:]])


class Adim:
    def __init__(self, tur):
        self.tur = tur


class DarAdim:
    __slots__ = ("tur",)

    def __init__(self, tur):
        self.tur = tur


G = gorevler()
BICIM = {
    "liste, paylaşılan dizgi": ([list(g) for g in G], lambda y: [list(g) for g in y]),
    "liste, ayrı dizgi": ([[ayri_dizgi(a) for a in g] for g in G],
                          lambda y: [list(g) for g in y]),
    "sözlük, paylaşılan dizgi": ({i: list(g) for i, g in enumerate(G)},
                                 lambda y: [y[i] for i in sorted(y)]),
    "nesne, sözlüklü": ([[Adim(a) for a in g] for g in G],
                        lambda y: [[a.tur for a in g] for g in y]),
    "nesne, yuvalı": ([[DarAdim(a) for a in g] for g in G],
                      lambda y: [[a.tur for a in g] for g in y]),
    "tek bayt dizisi": (bytes(1 if a == ISLEMCI else 0 for g in G for a in g),
                        lambda y: [[ISLEMCI if b else GC for b in y[i * 10:i * 10 + 10]]
                                   for i in range(8)]),
}

print(f"{'biçim':<26s} {'nesne':>6s} {'çözülen dizi aynı':>18s} {'tik / örtüşen':>14s}")
for ad, (yapi, coz) in BICIM.items():
    sayi, _ = nesneleri_say(yapi)
    d = coz(yapi)
    tik, ortusen, _, _ = kosum(d, 8, 1)
    print(f"{ad:<26s} {sayi:6d} {str(d == G):>18s} {f'{tik} / {ortusen}':>14s}")

print()
for ad in ("liste, paylaşılan dizgi", "nesne, sözlüklü", "nesne, yuvalı"):
    print(f"{ad:<26s} {nesneleri_say(BICIM[ad][0])[1]}")

print()
p = BICIM["liste, paylaşılan dizgi"][0]
a = BICIM["liste, ayrı dizgi"][0]
print(f"paylaşılan biçimde ilk adım kurgunun nesnesiyle aynı -> {p[0][0] is G[0][0]}")
print(f"ayrı biçimde aynı -> {a[0][0] is G[0][0]}, eşit -> {a[0][0] == G[0][0]}")
b = BICIM["tek bayt dizisi"][0]
print(f"bayt dizisinden iki kez alınan dilim aynı nesne -> {b[0:10] is b[0:10]}, "
      f"eşit -> {b[0:10] == b[0:10]}")
print(f"toplam adım {sum(len(g) for g in G)}, en az nesneli biçim "
      f"{min(nesneleri_say(y)[0] for y, _ in BICIM.values())}, en çok "
      f"{max(nesneleri_say(y)[0] for y, _ in BICIM.values())}")
```

```
biçim                       nesne  çözülen dizi aynı  tik / örtüşen
liste, paylaşılan dizgi        11               True        31 / 49
liste, ayrı dizgi              89               True        31 / 49
sözlük, paylaşılan dizgi       19               True        31 / 49
nesne, sözlüklü               172               True        31 / 49
nesne, yuvalı                  91               True        31 / 49
tek bayt dizisi                 1               True        31 / 49

liste, paylaşılan dizgi    {'list': 9, 'str': 2}
nesne, sözlüklü            {'list': 9, 'Adim': 80, 'dict': 80, 'str': 3}
nesne, yuvalı              {'list': 9, 'DarAdim': 80, 'str': 2}

paylaşılan biçimde ilk adım kurgunun nesnesiyle aynı -> True
ayrı biçimde aynı -> False, eşit -> True
bayt dizisinden iki kez alınan dilim aynı nesne -> False, eşit -> True
toplam adım 80, en az nesneli biçim 1, en çok 172
```

## Sonuç Değişmedi

Tablonun sağ iki sütunu ölçümün geçerlilik koşuludur. Altı biçimin altısı da çözüldüğünde
ortak tanımın dizisiyle **aynı** çıkıyor, ve altısı da çizelgeleyiciye aynı yanıtı
verdiriyor: **31 tik / 49 örtüşen adım.**

Bu, sol sütundaki farkın ne olduğunu tanımlar. Nesne sayısı 1 ile 172 arasında değişirken
işin sonucu hiç değişmiyor. Ölçülen şey **aynı sonucu tutmanın bedelidir**, sonucun kendisi
değil. Bu ayrım olmadan tablo bir karşılaştırma değil, altı ayrı ölçüm olurdu.

Sütunun tabloda durması bir biçimcilik değil. Bellek ölçümlerinde en sık yapılan yanlış,
biçimi değiştirirken veriyi de sessizce değiştirmektir — bir alanı düşürmek, bir dizgiyi
kısaltmak, bir görevi eksik kurmak. Böyle bir ölçümde nesne sayısı gerçekten düşer, ama
düşme nedeni biçim değil eksilen veridir. `çözülen dizi aynı` sütunu bunu her satırda
sınıyor; **True** olmayan bir satır tablodan çıkarılırdı.

## Paylaşımın Ödediği

İlk iki satır tek bir farkla ayrılıyor. Yapı aynı — bir dış liste, sekiz iç liste, seksen
yuva. Değerler de aynı; alt bloktaki `eşit -> True` bunu söylüyor. Ayrı olan tek şey
nesnelerdir: paylaşılan biçimde 80 yuva **iki** dizgi nesnesini gösteriyor, ayrı biçimde
**seksen** dizgiyi.

Sayı **11**'den **89**'a çıkıyor: **78 nesne fazla**, sıfır bilgi karşılığında. Alt bloktaki
kimlik sınaması nedenini gösteriyor — ilk biçimde adım, kurgunun ürettiği nesnenin ta
kendisi; ikinci biçimde eşit ama ayrı bir nesne.

Bu, gerçek programlarda en sık karşılaşılan bellek örüntüsüdür. Bir dosyadan ya da bir
iletiden okunan alanlar birbirine eşit olsa bile ayrı nesnelerdir; okuma sırasında her
biri yeniden kurulur. Aynı değerin tekrar ettiği bir sütunda paylaşımı yeniden kurmak — az
sayıda değişmez değeri bir kez üretip her yerde onu göstermek — nesne sayısını doğrudan
düşürür.

## Nesne Başına Yükü Kim Ödüyor

Dördüncü ve beşinci satırlar aynı sınıfın iki kuruluşu. Her adım bir örnek; fark yalnız
niteliklerin nerede tutulduğu.

Sözlüklü kuruluş **172**, yuvalı kuruluş **91** nesne tutuyor. Aradaki **81**'in nereden
geldiğini tip dökümü söylüyor: sözlüklü biçimde `dict` sayısı **80**'dir — örnek başına bir
sözlük — ve nitelik adı olan bir dizgi de fazladan sayılıyor, bu yüzden `str` sayısı 2 değil
**3**. Yuvalı biçimde `dict` satırı hiç yok.

Nitelik adları önceden bildirildiğinde örneğin ayrıca bir sözlük taşımasına gerek kalmaz.
Kazanç, örnek sayısıyla çarpılarak büyür: burada seksen örnek seksen sözlükten kurtuluyor.
Bedeli esnekliktir — bildirilmemiş bir nitelik sonradan eklenemez.

Üçüncü satır aynı yükün başka bir yüzünü gösteriyor. Dış kabı listeden sözlüğe çevirmek
nesne sayısını **11**'den **19**'a çıkarıyor. Fazladan sekiz nesne, sekiz **anahtarın**
kendisidir: liste konumları nesne değildir, sözlük anahtarları nesnedir. Erişim aynı,
sonuç aynı, sekiz nesne fazla.

## Tek Nesnenin Bedeli

Son satır 80 adımı **tek** nesnede tutuyor. Bu, tablodaki en düşük sayı ve nedeni açık:
bayt dizisinin içindeki 80 değer ayrı nesne değil, tek bir nesnenin içeriğidir. Yapı
sınırları — hangi on adımın hangi göreve ait olduğu — aritmetikle geri kazanılıyor.

Bedeli alt bloktaki son kimlik sınamasında duruyor: aynı dilim iki kez alındığında ortaya
**iki ayrı nesne** çıkıyor. Değişmez bir bayt dizisinden parça okumak, her okumada yeni bir
nesne kurmak demektir. Yani bir nesnede duran yapı, **okundukça** nesne üretir; ayakta
duran sayı düşerken var edilen sayı yükselir.

İki ölçünün ayrı olması burada işe yarıyor. Bir yapıyı seçerken sorulacak soru tek değildir:
elde ne kadar tutuluyor, ve o tutulan şeye erişmek her seferinde ne üretiyor? Bayt dizisi
ilkinde en iyi, ikincisinde en kötü seçenektir; paylaşılan dizgili liste ikisinde de ortanın
üstündedir ve **11** nesneyle 80 adımı doğrudan erişilebilir tutar.

Altı satır bir sıralama değil, bir eksen veriyor. Bir uçta yapı bilgisinin tümü nesnelerde
duruyor ve erişim bedava; öbür uçta yapı bilgisi koda taşınmış, nesne bir taneye inmiş ve
erişimin bedeli her okumaya dağılmış. Ölçüm hangi ucun doğru olduğunu söylemez — hangi ucun
neye mal olduğunu söyler. Kararı veren şey, aynı yapıya kaç kez bakılacağıdır.

## Özet

- Bu kurs bellek yükünü **ölçülen baytla** değil **ayakta duran nesne sayısıyla** ölçer;
  bayt karşılığı ortama bağlıdır, nesne sayısı yapının kendisinden gelir ve her koşumda
  aynı çıkar.
- Aynı 80 adım altı biçimde **1** ile **172** nesne arasında tutulabiliyor, ve altısı da
  çizelgeleyiciye aynı **31 tik / 49 örtüşen adım** sonucunu verdiriyor.
- Paylaşımı kaybetmek yapıyı değiştirmeden **11** nesneyi **89**'a çıkarır: eşit ama ayrı
  seksen dizgi, sıfır bilgi karşılığında **78** fazladan nesnedir.
- Örnek başına sözlük tutmak **172**, nitelik adlarını önceden bildirmek **91** nesne
  demektir; aradaki **81**, seksen örnek sözlüğü ile bir nitelik adıdır.
- Dış kabı listeden sözlüğe çevirmek sekiz anahtar nesnesi ekler; liste konumu nesne
  değildir, sözlük anahtarı nesnedir.
- Tek nesnede tutulan yapı ayakta duranı **1**'e indirir ama her okumada yeni nesne üretir;
  tutma ölçüsüyle üretme ölçüsü ayrı yönlere çekebilir.

## Sonraki Adım

Buraya kadar iki sayı ölçüldü: bir işlevin kaç kez çağrıldığı ve bir yapının kaç nesne
tuttuğu. İkisi de aynı yöne işaret ediyor — sıcak yol, `islemci_adimi_mi` çağrısının 322
kez döndüğü yerdir. Peki o yol daha aza indirilebilir mi? Bir sıcak yolu dilin dışına, daha
alt bir seviyeye taşımak sık başvurulan bir yoldur ve kazancı çoğu kez süreyle anlatılır.
Sonraki ders bunu süreyle değil **modelde adım olarak** ölçer: sıcak yolun adım sayısı
düştüğünde toplam tik ne oluyor, ve sınırdan geçmenin kendisi ne kadarını geri alıyor?
