4 - Dinamik Bellek Yönetimi
2025
Bellek yönetimi, yazılımcıların en önemli görevlerinden biridir. Özellikle C gibi dillerde, yazılımcılar belleği manuel olarak yönetmek zorundadır. Bu, karmaşık ve hataya açık bir işlem olabilmektedir.
Statik (Sabit) Bellek Yönetimi Yetersizlikleri:
Dinamik Bellek Yönetimi Çözümü:
Yüksek seviyeli dillerde (Java, Python vb.) dinamik bellek yönetimi otomatik olarak yapılır. Ancak C dilinde yazılımcı bu yönetimi kendisi yapmalıdır.
Özellik | Statik Bellek Yönetimi | Dinamik Bellek Yönetimi |
---|---|---|
Bellek Ayırma | Derleme zamanında (compile-time) | Çalışma zamanında (runtime) |
Bellek Miktarı | Sabit, program başında belirlenir | Değişken, program sırasında değişebilir |
Esneklik | Düşük | Yüksek |
Kontrol | Otomatik (derleyici tarafından) | Manuel (programcı tarafından) |
Kullanım Alanı | Yerel değişkenler, global değişkenler | Değişken boyutlu veri yapıları, runtime boyut belirleme |
C dilinde dinamik bellek yönetimi için standart kütüphanede (stdlib.h) bulunan bazı fonksiyonlar kullanılır:
malloc()
: Bellek ayırmacalloc()
: Bellek ayırma ve sıfırlamarealloc()
: Ayrılmış belleği yeniden boyutlandırmafree()
: Ayrılmış belleği serbest bırakmamalloc()
- Bellek AyırmaGörev: Belirtilen boyutta ham (initialize edilmemiş) bellek bloğu ayırır.
Sözdizimi:
size
: Ayrılacak bellek bloğunun boyutu (byte cinsinden).void*
işaretçi döner.NULL
işaretçi döner. Dönüş değerini kontrol etmek çok önemlidir!int
için bellek ayırma#include <stdio.h>
#include <stdlib.h>
int main() {
int *dizi;
int boyut = 10;
// 10 int için bellek ayır (10 * sizeof(int) byte)
dizi = (int*)malloc(boyut * sizeof(int));
// Bellek ayrılıp ayrılamadığını kontrol et
if (dizi == NULL) {
printf("Bellek ayırma başarısız!\n");
return 1; // Hata kodu ile çıkış
}
printf("Bellek başarıyla ayrıldı.\n");
// Diziyi kullan... (örneğin değer atama)
for (int i = 0; i < boyut; i++) {
dizi[i] = i * 2;
}
// Diziyi yazdır
for (int i = 0; i < boyut; i++) {
printf("%d ", dizi[i]);
}
printf("\n");
// Belleği serbest bırakmayı UNUTMA!
free(dizi);
dizi = NULL; // Serbest bırakılan işaretçiyi NULL yapmak iyi bir uygulamadır.
return 0; // Başarılı çıkış
}
calloc()
- Bellek Ayırma ve SıfırlamaGörev: Belirtilen sayıda ve boyutta bellek bloğu ayırır ve belleği sıfırlar (0 ile doldurur).
Sözdizimi:
num
: Ayrılacak eleman sayısı.size
: Her bir elemanın boyutu (byte cinsinden).malloc()
ile aynı şekilde, başarılıysa adres, başarısızsa NULL
.Temel Fark: calloc()
ayrılan belleği sıfırlar, malloc()
sıfırlamaz.
int
için bellek ayırma ve sıfırlamarealloc()
- Belleği Yeniden BoyutlandırmaGörev: Önceden ayrılmış bir bellek bloğunun boyutunu değiştirir (büyütür veya küçültür).
Sözdizimi:
ptr
: Yeniden boyutlandırılacak önceden ayrılmış bellek bloğunun işaretçisi.new_size
: Yeni istenen boyut (byte cinsinden).void*
işaretçi döner. Bu adres ptr ile aynı olmayabilir!NULL
işaretçi döner. Orijinal bellek bloğu değişmeden kalır.realloc()
yeni bir bellek bloğu ayırabilir ve içeriği eski bloktan yeni bloğa kopyalayabilir.new_size
0 ise ve ptr
NULL
değilse, realloc()
free(ptr)
gibi davranır (belleği serbest bırakır).ptr
NULL
ise, realloc(NULL, size)
malloc(size)
gibi davranır (yeni bellek ayırır). printf("Başlangıç dizisi: ");
for (int i = 0; i < boyut; i++) {
printf("%d ", dizi[i]);
}
printf("\n");
// Dizinin boyutunu 10'a çıkar
boyut = 10;
int *yeni_dizi = (int*)realloc(dizi, boyut * sizeof(int)); // realloc'un dönüş değerini kontrol et!
if (yeni_dizi == NULL) {
printf("Bellek yeniden boyutlandırma başarısız!\n");
free(dizi); // Orijinal belleği serbest bırak
return 1;
}
dizi = yeni_dizi; // İşaretçiyi güncelle (önemli!)
free()
- Belleği Serbest BırakmaGörev: Dinamik olarak ayrılmış bir bellek bloğunu sisteme geri verir (serbest bırakır). Bu bellek, başka dinamik bellek istekleri için tekrar kullanılabilir hale gelir.
Sözdizimi:
ptr
: Serbest bırakılacak bellek bloğunun başlangıç adresini gösteren işaretçi. Bu işaretçi daha önce malloc()
, calloc()
veya realloc()
tarafından döndürülmüş olmalıdır.ptr
NULL
ise, free(NULL)
hiçbir şey yapmaz (güvenlidir).#include <stdio.h>
#include <stdlib.h>
int main() {
int *dizi;
dizi = (int*)malloc(10 * sizeof(int));
if (dizi == NULL) {
printf("Bellek ayırma başarısız!\n");
return 1;
}
// ... Diziyi kullan ...
// Belleği serbest bırak
free(dizi);
dizi = NULL; // İşaretçiyi NULL yapmak iyi bir uygulama
return 0;
}
Bellek Sızıntısı (Memory Leak):
free()
ile serbest bırakılmaması durumunda oluşur.Sarkan İşaretçi (Dangling Pointer):
Çift Serbest Bırakma (Double Free):
free()
ile serbest bırakmaya çalışmak.İyi Uygulamalar:
free()
ile serbest bırakın.malloc()
, calloc()
, realloc()
dönüş değerlerini kontrol edin. NULL
dönmüşse bellek ayırma başarısız olmuştur.NULL
yapın (sarkan işaretçileri önlemek için).Dinamik Diziler (Resizable Arrays):
malloc()
ile başlangıç boyutu kadar bellek ayır, realloc()
ile boyutu gerektiğinde büyüt.Dinamik Karakter Dizileri (Strings):
malloc()
ile yeterli bellek ayır, realloc()
ile metin uzadıkça belleği büyüt.Bağlı Listeler, Ağaçlar, Grafikler gibi Veri Yapıları:
malloc()
, calloc()
, realloc()
, free()
fonksiyonları ile yapılır.