Bölüm 8: Bellek Yönetimi
Giriş
Öğrenme Çıktıları
Bellek hiyerarşisini, adres uzayı soyutlamasını, koruma ve yer değiştirme problemlerini açıklamak.
Derleme, yükleme ve yürütme zamanı bağlamayı; mantıksal/fiziksel adresi ve MMU'nun taban-limit denetimini hesaplamak.
Dinamik yüklemeyi, statik ve dinamik bağlamayı, PLT/GOT ile paylaşımlı kütüphaneleri ve takası tartışmak.
İlk, sonraki, en iyi, en kötü uyan algoritmalarını uygulamak; iç/dış parçalanmayı, biteşlemi ve buddy sistemini çözümlemek.
Adresi (p, d) olarak bölmek, sayfa tablosu ve TLB ile çeviri yapmak, etkili erişim süresini hesaplamak.
Hiyerarşik, karma ve ters tabloları; x86-64 dört/beş seviyeli sayfalamayı, büyük sayfaları, kesimlemeyi ve ARMv8'i karşılaştırmak.
Giriş
Bellek Hiyerarşisi ve Bellek Yöneticisi
- CPU'nun doğrudan erişebildiği depolama yalnızca yazmaçlar ve ana bellektir; disk ancak G/Ç ile.
- Bellek birimi yalnızca bir akış görür: adres + okuma ya da adres + veri + yazma. Adresin nereden geldiğini bilmez.
- Yazmaç bir saat döngüsünde okunur; DRAM erişimi yüzlerce döngü sürer ve CPU durur (stall). Aradaki boşluğu önbellek kapatır.
- Programcı belleğin sınırsız, hızlı, kalıcı ve korumalı olmasını ister; gerçek çözüm hiyerarşidir.
- Bellek yöneticisi: boş/dolu alanı izler, süreçlere tahsis eder, geri alır, süreçleri birbirinden korur.
Değerler 2026 itibarıyla tipik mertebelerdir; çekirdek ve modele göre değişir. Önbellek donanımca yönetilir, bu bölümün konusu ana bellektir.
Giriş
Soyutlama Olmadan Bellek
- İlk bilgisayarlarda (1960'lar öncesi ana çerçeveler, 1980'ler öncesi kişisel bilgisayarlar) her program fiziksel belleği doğrudan görürdü:
MOV REGISTER1, 1000fiziksel 1000 adresini okur. - Bellekte aynı anda iki program olamaz: ikisi de aynı fiziksel adreslere yazar, biri diğerini ezer.
- (a) ve (c)'de kullanıcı programındaki bir hata işletim sistemini çökertebilir.
- (b) bazı gömülü sistemlerde, (c) MS-DOS'lu ilk PC'lerde kullanıldı (BIOS sürücüleri ROM'da).
- Bugün de MMU'suz mikrodenetleyiciler böyle çalışır; çoğu en azından MPU (bellek koruma birimi) ile bölgeleri korur.
Giriş · Adım adım
Yer Değiştirme Problemi
A ve B 16 KB'lık iki program; ikisi de 0 adresinden başlayacağı varsayılarak derlendi.
İşletim sistemi önce A'yı 0'a, ardından B'yi hemen üstüne, 16384'e yükler.
B'nin ilk komutu JMP 28 mutlak adres kullanır: fiziksel 28'e, yani A'nın ADD komutuna atlar ve program çöker.
Statik yer değiştirme (IBM 360): yükleyici her adres sözcüğüne başlangıç adresini ekler: JMP 16412. Yükleme yavaşlar.
Ama MOV REG1, 28'deki 28 bir sabittir, değişmemelidir. Yükleyici hangi sözcüğün adres olduğunu bilmek için ek yer değiştirme bilgisi ister.
Adres Uzayı
Adres Uzayı: Taban ve Limit Yazmaçları
- Adres uzayı: bir sürecin kullanabileceği adresler kümesi. Her sürecin kendine ait, diğerlerinden bağımsız adres uzayı vardır.
- Çözülmesi gereken iki problem: koruma (başkasının alanına erişememe) ve yer değiştirme (her yere yüklenebilme).
- En basit donanım: taban (başlangıç fiziksel adresi) ve limit (uzunluk) yazmaçları. Program bitişik bir alana olduğu gibi yüklenir.
- Yazmaçlar yalnızca çekirdek kipinde ayrıcalıklı komutlarla yüklenir; bağlam değişiminde yeni sürecin değerleri konur.
- CDC 6600 böyle çalışıyordu. Intel 8088'in kesim yazmaçları ise yalnızca taban idi; limit olmadığından koruma yoktu.
Adres Uzayı · Adım adım
Donanımsal Adres Koruması
300.040 = taban: ilk geçerli adres; iki karşılaştırma da geçer, erişim yapılır.
356.000 aralığın içinde; erişim yapılır. Denetim her erişimde, paralel donanımla yapılır.
420.939 = taban + limit − 1: son geçerli adres.
420.940 = taban + limit: ikinci karşılaştırma başarısız → tuzak. Çekirdek süreci genellikle sonlandırır (Unix'te SIGSEGV).
299.999 tabandan küçük: ilk karşılaştırma başarısız → başka sürecin alanı korunur.
Kullanıcı kipindeki her erişim denetlenir. Çekirdek kipinde denetim yapılmaz; işletim sistemi tüm belleğe erişebilmelidir (Silberschatz Şekil 9.2).
Adres Uzayı
Adres Bağlama Zamanları
| Bağlama zamanı | Üretilen kod | Konum değişirse | Donanım |
|---|---|---|---|
| Derleme | Mutlak kod (ör. MS-DOS .COM) | yeniden derle | gerekmez |
| Yükleme | Yeri değiştirilebilir kod; yükleyici adresleri düzeltir | yeniden yükle | gerekmez |
| Yürütme | Mantıksal adresler; süreç çalışırken taşınabilir | hiçbir şey | MMU (taban-limit, sayfalama) |
Kaynakta adresler semboliktir (count); derleyici onları göreli adrese (“modül başından 14 bayt”), bağlayıcı/yükleyici mutlak adrese (74014) bağlar. Modern genel amaçlı sistemlerin hepsi yürütme zamanı bağlama kullanır.
Adres Uzayı
Mantıksal ve Fiziksel Adres, MMU
- Mantıksal (sanal) adres: CPU'nun ürettiği adres. Fiziksel adres: bellek biriminin gördüğü, adres yazmacına (MAR) yüklenen adres.
- Derleme ve yükleme zamanı bağlamada ikisi aynıdır; yürütme zamanı bağlamada farklıdır.
- Mantıksal adres uzayı: programın ürettiği adresler kümesi; fiziksel adres uzayı: bunlara karşılık gelen fiziksel adresler.
- Çalışma anındaki dönüşümü MMU (bellek yönetim birimi) donanımı yapar. Program fiziksel adresleri hiç görmez.
- Bugünkü işlemcilerde MMU, TLB'leri ve sayfa tablosu yürüyücüsüyle birlikte her çekirdeğin içindedir.
Adres Uzayı · Adım adım
MMU ile Dinamik Yer Değiştirme
Mantıksal 346 < 3.000 → fiziksel 346 + 14.000 = 14.346. Program 0 ile 2.999 arasını görür.
2.999 son geçerli mantıksal adres → 16.999.
3.500 ≥ limit → toplama yapılmadan tuzak. Karşılaştırma mantıksal adres üzerinden olduğu için taban değeri ne olursa olsun aynıdır.
Önceki örnekteki B programı: taban = limit = 16.384. JMP 28 değişmeden kalır, MMU 28 + 16.384 = 16.412 üretir. Statik yer değiştirmeye gerek kalmaz.
Silberschatz'ın yer değiştirme yazmacı Tanenbaum'un taban yazmacıdır. Her erişimde bir toplama ve bir karşılaştırma gerekir; toplama, elde yayılımı yüzünden özel devre olmadan yavaştır.
Bağlama ve Yükleme · Kodu adım adım çalıştır
Dinamik Yükleme
#include <dlfcn.h> #include <stdio.h> int main(void) { void *h = dlopen("libm.so.6", RTLD_LAZY); if (!h) { puts(dlerror()); return 1; } double (*kok)(double) = (double (*)(double)) dlsym(h, "sqrt"); printf("%.3f\n", kok(2.0)); dlclose(h); return 0; }
Program başladı: adres uzayında yalnız main, libc, yığıt (heap) ve yığın (stack) var; libm yüklü değil.
dlopen: dinamik bağlayıcı (ld.so) dosyayı bulur, mmap ile adres uzayına eşler. Yükleme şimdi, programın isteğiyle olur.
dlsym sembol tablosunda sqrt'u arar ve o sürecin adres uzayındaki adresini döndürür.
İşlev işaretçisiyle çağrı yapılır; çıktı 1.414.
dlclose: başvuru sayısı 0'a inince kütüphane adres uzayından çıkarılır.
Rutin çağrılana kadar belleğe alınmaz; kullanılmayan kod hiç yüklenmez. Donanım desteği gerekmez, program böyle tasarlanır; işletim sistemi kütüphane sağlar (dlopen, Windows'ta LoadLibrary/GetProcAddress). glibc 2.34'ten beri -ldl gerekmez.
Bağlama ve Yükleme
Statik ve Dinamik Bağlama
| Statik bağlama | Dinamik bağlama | |
|---|---|---|
| Kim, ne zaman? | Bağlayıcı (ld), derlemeden sonra | Dinamik bağlayıcı (ld.so), yüklemede/çalışırken |
| Dosya | .a, .lib | .so, .dll, .dylib |
| Bellek | Her programda ayrı kopya | Kod sayfaları bir kez bellekte, paylaşılır |
| Güncelleme | Yeniden bağlamak gerekir | Kütüphaneyi değiştirmek yeter (sürüm: soname) |
| Risk | Büyük dosya, güvenlik yaması gecikir | Sürüm uyuşmazlığı (“DLL cehennemi”) |
- Statik: kütüphane rutinleri ikili dosyaya kopyalanır (
ld *.o -lc -lm). - Dinamik: dosyada yalnızca bir taslak (stub) kalır; adres yürütme zamanında çözülür.
Bağlama ve Yükleme · Adım adım
Tembel Bağlama: PLT ve GOT
Derleyici printf'in adresini bilmez; çağrı küçük bir PLT (procedure linkage table) taslağına gider. Pptx'teki stub budur.
PLT, GOT (global offset table) içindeki adrese dolaylı atlar. Başlangıçta GOT girdisi çözücüyü gösterir.
ld.so çözücüsü sembolü yüklü kütüphanelerde arar, bulduğu adresi GOT'a yazar.
Çözücü printf'e atlar. Kod sayfaları değişmedi; yalnızca sürece özel GOT sayfası değişti, bu yüzden kod paylaşılabilir kalır.
Sonraki çağrılar PLT → GOT → printf: yalnızca bir dolaylı atlama. Güvenlik için birçok dağıtım -z now (tam RELRO) ile tüm sembolleri yüklemede çözüp GOT'u salt okunur yapar.
Kitaplardaki “taslak kendini rutinin adresiyle değiştirir” anlatımı kavramsaldır; ELF sistemlerinde değişen kod değil, GOT girdisidir. Bunu işletim sistemi değil kullanıcı alanındaki dinamik bağlayıcı yapar.
Bağlama ve Yükleme
Kütüphane Oluşturma: Statik ve Paylaşımlı
Statik kütüphane
$ gcc -c func.c -o func.o $ ar rcs libfunc.a func.o $ gcc main.c -o main -static -L. -lfunc $ ./main
arnesne dosyalarını arşivler; bağlayıcı yalnızca gereken nesneleri kopyalar.-staticlibc'nin de statik sürümünü (libc.a) ister.
Paylaşımlı kütüphane
$ gcc -fPIC -c func.c -o func.o
$ gcc -shared -o libfunc.so func.o
$ gcc main.c -o main -L. -lfunc
$ export LD_LIBRARY_PATH=$(pwd)
$ ./main
$ ldd ./main (libfunc.so => ./libfunc.so)-fPIC: konumdan bağımsız kod; mutlak adres yerine PC'ye göreli adresleme, veriye GOT üzerinden erişim.- Böylece aynı fiziksel sayfa her süreçte farklı sanal adrese eşlenebilir (ASLR).
LD_LIBRARY_PATHyerine kalıcı çözüm:-Wl,-rpath,'$ORIGIN'ya daldconfig.
Modern dağıtımlar programları da konumdan bağımsız (PIE) derler; böylece programın kendisi de ASLR ile rastgele adrese yüklenir.
Takas
Takas (Swapping)
- Standart takas: bir sürecin tamamı geçici olarak yedekleme deposuna (disk) yazılır, sonra geri getirilir.
- Toplam bellek ihtiyacı fiziksel belleği aşabilir; çoklu programlama derecesi artar.
- Geri gelen süreç başka adrese yerleşebilir → yürütme zamanı bağlama gerekir.
- Bedel: 100 MB süreç, 50 MB/s disk → 2 s dışarı + 2 s içeri = 4 s (Silberschatz).
- Bekleyen G/Ç'si olan süreç takas edilmez (DMA eski adrese yazar) ya da G/Ç çekirdek tamponlarından yapılır.
Takas
Sayfa Takası ve Modern Sistemler
- Bütün süreci taşımak bugün kabul edilemez: 1 GiB süreç, 3 GB/s NVMe → gidiş-dönüş ≈ 0,72 s.
- Linux, Windows, macOS sayfa takas eder: yalnızca uzun süredir kullanılmayan (soğuk) sayfalar dışarı gider, 4 KiB'lık bir sayfa onlarca µs'de gelir.
- Diske gitmeden önce sıkıştırma: Linux zswap ve zram, Windows bellek sıkıştırma, macOS sıkıştırıcı.
- Mobil: flaş ömrü ve enerji yüzünden geleneksel takas yok ya da sınırlı; Android zram +
lmkd, iOS sıkıştırma + uygulama sonlandırma (jetsam). - Sayfa düzeyinde takas ve sayfa değiştirme algoritmaları Bölüm 9'un konusudur.