↑↓ seç · Enter aç · Esc kapat

Mutlu Tekin
Mutlu Tekin
← Yazılar

Bölüm 13 — Konu 62: Memory Model & Performans — Garbage Collection, `const` Nesnelerin Bellek Avantajı

5 dk okuma #dart
Dizi · 60/64 Dart Türkçe Tutorial
  1. Bölüm 1 — Konu 1: Dart Nedir, Nerede Kullanılır, Neden Flutter Bu Dili Seçti
  2. Bölüm 1 — Konu 2: Ortam Kurulumu (Dart SDK, DartPad, Terminal ile Çalıştırma)
  3. Bölüm 1 — Konu 3: İlk Program (`main()`, `print()`, Dosya Yapısı)
  4. Bölüm 1 — Konu 4: Yorum Satırları, Temel Sözdizimi Kuralları
  5. Bölüm 2 — Konu 5: Değişken Tanımlama — `var`, `final`, `const` Farkı
  6. Bölüm 2 — Konu 6: Temel Tipler — `int`, `double`, `String`, `bool`
  7. Bölüm 2 — Konu 7: Tip Çıkarımı (Type Inference) ve Açık Tip Belirtme
  8. Bölüm 2 — Konu 8: `dynamic` ve `Object` — Ne Zaman Kullanılır, Ne Zaman Kaçınılır
  9. Bölüm 2 — Konu 9: Null Safety Temelleri (`?`, `!`, `late`'e Giriş)
  10. Bölüm 3 — Konu 10: Aritmetik, Atama, Karşılaştırma, Mantıksal Operatörler
  11. Bölüm 3 — Konu 11: `if / else if / else`
  12. Bölüm 3 — Konu 12: `switch` / `switch expression` (Modern Dart)
  13. Bölüm 3 — Konu 13: Ternary Operatör, `??`, `??=`, `?.`
  14. Bölüm 3 — Konu 14: `for`, `while`, `do-while` Döngüleri
  15. Bölüm 4 — Konu 16: `List` — Oluşturma, Erişim, Temel Metodlar
  16. Bölüm 4 — Konu 17: `Set` — Benzersiz Eleman Mantığı
  17. Bölüm 4 — Konu 18: `Map` — Key-Value Yapılar
  18. Bölüm 4 — Konu 19: Koleksiyon Üzerinde `for-in`, `forEach`
  19. Bölüm 4 — Konu 20: Spread Operatörü (`...`, `...?`) ve Collection If/For
  20. Bölüm 5 — Konu 21: Fonksiyon Tanımlama, Parametreler (Positional, Named, Optional)
  21. Bölüm 5 — Konu 22: Varsayılan Parametre Değerleri (Derinlemesine)
  22. Bölüm 5 — Konu 23: Arrow Function (`=>`) Sözdizimi
  23. Bölüm 5 — Konu 24: Fonksiyonlar Birinci Sınıf Vatandaş — Değişkene Atama, Parametre Olarak Geçme
  24. Bölüm 5 — Konu 25: Anonim Fonksiyonlar ve Closure Kavramı (Derinlemesine)
  25. Bölüm 5 — Konu 26: Recursion (Özyineleme)
  26. Bölüm 6 — Konu 27: Class Tanımlama, Constructor (Varsayılan, Named, Factory)
  27. Bölüm 6 — Konu 28: Alanlar (Fields), Metodlar, `this` Kullanımı (Derinlemesine)
  28. Bölüm 6 — Konu 29: Initializer List, Constructor Kısayolları (Derinlemesine)
  29. Bölüm 6 — Konu 30: Getter / Setter
  30. Bölüm 6 — Konu 31: Statik Üyeler (`static`)
  31. Bölüm 7 — Konu 32: Kalıtım (`extends`), `super` Kullanımı
  32. Bölüm 7 — Konu 33: Metod Override Etme, `@override`
  33. Bölüm 7 — Konu 34: Soyut Sınıflar (`abstract class`)
  34. Bölüm 7 — Konu 35: Interface Mantığı (`implements`)
  35. Bölüm 7 — Konu 36: Mixin (`with`)
  36. Bölüm 7 — Konu 37: `enum` — Basit ve Gelişmiş (Metotlu Enum'lar)
  37. Bölüm 8 — Konu 38: `try / catch / finally`, `throw`
  38. Bölüm 8 — Konu 39: Özel Exception Sınıfları Yazma
  39. Bölüm 8 — Konu 40: Sound Null Safety Derinlemesine — `late`, `required`, Non-Nullable Varsayılan Davranış
  40. Bölüm 8 — Konu 41: `assert` ile Geliştirme Zamanı Kontrolleri
  41. Bölüm 9 — Konu 42: Generic Sınıflar ve Fonksiyonlar
  42. Bölüm 9 — Konu 43: Generic Sınırlamalar (`<T extends ...>`)
  43. Bölüm 9 — Konu 44: Dart'ın Built-in Generic Koleksiyonları Nasıl Çalışır
  44. Bölüm 10 — Konu 45: `Future` Kavramı, `async`/`await`
  45. Bölüm 10 — Konu 46: `Future.then`, Hata Yönetimi (`catchError`)
  46. Bölüm 10 — Konu 47: `Stream` Temelleri, `async*`, `yield`
  47. Bölüm 10 — Konu 48: `StreamController`, Broadcast Stream
  48. Bölüm 11 — Konu 49: `map`, `where`, `reduce`, `fold`
  49. Bölüm 11 — Konu 50: `sort`, Custom Comparator ile Sıralama
  50. Bölüm 11 — Konu 51: Iterable Kavramı Derinlemesine (Lazy Evaluation)
  51. Bölüm 11 — Konu 52: Cascade Notasyonu (`..`)
  52. Bölüm 12 — Konu 53: `pubspec.yaml`, pub.dev'den Paket Ekleme
  53. Bölüm 12 — Konu 54: Kütüphane Oluşturma, `import`/`export`, `part`/`part of`
  54. Bölüm 12 — Konu 55: Dart'ta Test Yazımı (`test` Paketi, Unit Test Mantığı)
  55. Bölüm 12 — Konu 56: Extension Methods
  56. Bölüm 12 — Konu 57: Dart'ın Derleme Modelleri (JIT vs AOT) ve Bunun Flutter'a Etkisi
  57. Bölüm 13 — Konu 59: Dart 3 Pattern Matching — Records, Destructuring, Sealed Classes, Exhaustive Switch
  58. Bölüm 13 — Konu 60: `Never` Tipi, `covariant` ve Generic Variance Detayları
  59. Bölüm 13 — Konu 61: Event Loop Derinlemesine — Microtask Queue vs Event Queue
  60. Bölüm 13 — Konu 62: Memory Model & Performans — Garbage Collection, `const` Nesnelerin Bellek Avantajı
  61. Bölüm 13 — Konu 63: Isolate'ler Arası Mesajlaşmanın Maliyeti ve `compute()`'un İç İşleyişi
  62. Bölüm 13 — Konu 64: FFI (Foreign Function Interface) — C Koduna Erişim
  63. Bölüm 13 — Konu 65: Sunucu Tarafında Dart — `dart:io`, `shelf` Paketiyle Basit Bir Backend/CLI Aracı Yazma
  64. Bölüm 13 — Konu 66: Derleyici & Analiz Araçları — `dart analyze`, Custom Lint Kuralları, `build_runner` Mimarisi
Dizinin sayfası →
İçindekiler 10 başlık
  1. Bellek Yönetimi Neden Önemli?
  2. Bellekte Nesneler Nasıl Saklanır? — Kısa Bir Zihinsel Model
  3. Garbage Collection (Çöp Toplama) Nedir?
  4. Dart'ın Generational (Nesiller Arası) Garbage Collector'ı
  5. const Nesnelerin Bellek Avantajı — Bölüm 2 ve Bölüm 6'ya Geri Dönüş
  6. Neden Bu, Performans Açısından Önemli?
  7. Değişmezlik (Immutability) ile Bellek Verimliliği Arasındaki İlişki
  8. hashCode ve == ile İlişki — Kısa Bir Not
  9. 🎯 Bu Dersten Çıkarılması Gerekenler
  10. 📝 Ödevler

Bellek Yönetimi Neden Önemli?

Bölüm 1'de, Flutter'ın Dart'ı seçme sebeplerinden biri olarak "UI-dostu garbage collection"dan bahsetmiştik. Şimdi bu ifadenin tam olarak ne anlama geldiğini işleyeceğiz.

Bellekte Nesneler Nasıl Saklanır? — Kısa Bir Zihinsel Model

Bir program çalışırken, oluşturduğun her nesne (Bölüm 6'da öğrendiğimiz class örnekleri, listeler, string'ler) bellekte (RAM'de) bir yer kaplar. Bu bellek alanına genelde heap (yığın) denir. Bir nesne oluşturduğunda, Dart runtime'ı heap'te ona yer ayırır; nesne artık kullanılmadığında, o bellek alanının boşaltılması (serbest bırakılması) gerekir — aksi halde bellek dolar ve program çöker (buna "memory leak" — bellek sızıntısı denir).

Garbage Collection (Çöp Toplama) Nedir?

C gibi bazı dillerde, belleği elle yönetmen gerekir — bir nesneyi oluşturur, işin bitince sen onu serbest bırakırsın. Bu, hataya çok açık bir süreçtir (unutulan bir serbest bırakma, bellek sızıntısına; erken bırakılan bir bellek, çökmeye yol açabilir).

Dart (Java, Python, JavaScript gibi birçok modern dil gibi), garbage collection (GC) kullanır — bu, artık kullanılmayan nesneleri otomatik olarak tespit edip belleği geri kazanan bir mekanizmadır. Sen elle bellek yönetmezsin; Dart runtime'ı, arka planda periyodik olarak çalışan bir "çöp toplayıcı" ile bunu senin için yapar.

dart
void ornekFonksiyon() {
  List<int> gecici = [1, 2, 3, 4, 5]; // heap'te yer ayrılır
  print(gecici.length);
} // fonksiyon bitince, 'gecici' artık erişilemez -> GC tarafından temizlenmeye ADAY olur

void main() {
  ornekFonksiyon();
  // 'gecici' listesi artık hiçbir yerden erişilemiyor, GC bir noktada bu belleği geri kazanır
}

Dart'ın Generational (Nesiller Arası) Garbage Collector'ı

Dart'ın GC'si, generational (nesillere dayalı) bir stratejiyle çalışır — bu, gerçek dünya gözleminden gelen bir optimizasyondur: çoğu nesne, çok kısa ömürlüdür (bir fonksiyon içinde oluşturulup hemen kullanılıp atılır), az sayıda nesne ise uzun süre yaşar (örneğin uygulamanın ana state'i).

Bu gözleme dayanarak, Dart'ın çöp toplayıcısı belleği iki bölgeye ayırır:

  1. Young generation (genç nesil / "new space"): Yeni oluşturulan nesneler buraya konur. Bu bölge sık sık ve çok hızlı taranır — çünkü buradaki nesnelerin çoğu kısa ömürlüdür, hızlıca "çöp" haline gelir.
  2. Old generation (eski nesil / "old space"): Young generation'da birkaç tarama sürecinden hayatta kalan (hâlâ kullanılan) nesneler buraya "terfi eder." Bu bölge, daha az sıklıkla taranır çünkü buradaki nesnelerin uzun süre yaşayacağı varsayılır.

Bu neden "UI-dostu"dur? Çünkü young generation taramaları (en sık yapılan tarama türü) çok hızlıdır ve genelde milisaniyelerin altında tamamlanır — bu, Flutter'ın her saniye onlarca kez ekranı yeniden çizmesi (widget'ları yeniden oluşturması) gerektiğinde, GC'nin UI'ı fark edilir şekilde durdurmamasını sağlar. Eğer GC, her taramada tüm belleği kontrol etseydi, bu "jank" (takılma) yaratabilirdi.

const Nesnelerin Bellek Avantajı — Bölüm 2 ve Bölüm 6'ya Geri Dönüş

Bölüm 2'de const'un "derleme zamanında sabit" anlamına geldiğini öğrenmiştik. Şimdi bunun bellek üzerindeki gerçek etkisini görelim:

dart
class Nokta {
  final double x;
  final double y;
  const Nokta(this.x, this.y); // const constructor
}

void main() {
  var n1 = const Nokta(1, 2);
  var n2 = const Nokta(1, 2);

  print(identical(n1, n2)); // true — AYNI bellek adresini işaret ediyorlar!
}

identical(), iki değişkenin tam olarak aynı nesneyi (bellekte aynı adresi) işaret edip etmediğini kontrol eder. const Nokta(1, 2) iki kere yazılmasına rağmen, Dart bunları tek bir nesne olarak "birleştiriyor" (deduplication/canonicalization) — çünkü const nesneler değişmezdir (immutable), bu yüzden aynı değerlere sahip iki const nesne, güvenle aynı bellek konumunu paylaşabilir.

Karşılaştıralım — const olmadan:

dart
class Nokta {
  final double x;
  final double y;
  Nokta(this.x, this.y); // const OLMAYAN constructor
}

void main() {
  var n1 = Nokta(1, 2);
  var n2 = Nokta(1, 2);

  print(identical(n1, n2)); // false — İKİ AYRI nesne, iki ayrı bellek alanı
}

Burada, her Nokta(1, 2) çağrısı yeni bir nesne oluşturur — iki ayrı bellek alanı kullanılır, ikisi de ayrı ayrı GC tarafından takip edilmesi gerekir.

Neden Bu, Performans Açısından Önemli?

1. Daha az bellek kullanımı: Aynı const değer, kodun her yerinde tekrar tekrar kullanılıyorsa (örneğin bir renk sabiti, bir boşluk değeri), her kullanımda yeni bir nesne oluşturmak yerine, tek bir paylaşılan nesne kullanılır.

2. Daha az GC yükü: Daha az nesne oluşturulduğu için, garbage collector'ın taraması gereken nesne sayısı azalır — bu, Bölüm 13'te öğrendiğimiz young generation taramalarının daha hızlı olmasına katkıda bulunur.

3. Flutter'da doğrudan performans etkisi: Flutter'da bir widget'ı const olarak işaretlediğinde (const Text("Merhaba") gibi — bunu Flutter tutorial'ında detaylı göreceğiz), Flutter bu widget'ın hiç değişmeyeceğini bilir ve onu yeniden oluşturmaktan (rebuild) tamamen kaçınabilir. Bu, Flutter'ın performans optimizasyonlarının en temel ve en etkili yöntemlerinden biridir — ve şimdi öğrendiğin bellek modeli sayesinde, neden bu kadar etkili olduğunu anlıyorsun.

Değişmezlik (Immutability) ile Bellek Verimliliği Arasındaki İlişki

Bu derste öğrendiğin şey, aslında daha genel bir prensibin somut bir örneği: değişmez (immutable) veri yapıları, paylaşılabilir (shareable) oldukları için bellek açısından daha verimlidir. Bölüm 2'de final/const'u öğrenirken "kodun okunabilirliği ve güvenliği için" demiştik — şimdi buna performans boyutunu da ekliyoruz. Bu, Dart'ın (ve Flutter'ın) neden "mümkün olduğunca const kullan" tavsiyesini bu kadar sık verdiğinin teknik temelidir.

hashCode ve == ile İlişki — Kısa Bir Not

identical()'ın kontrol ettiği "aynı bellek adresi", Bölüm 6'da gördüğümüz == operatöründen farklıdır — ==, varsayılan olarak (override edilmediği sürece) identical() ile aynı davranır, ama bir class kendi == operatörünü override ederse (örneğin "içerik eşitse eşit say" mantığıyla), iki farklı bellek adresindeki nesne == ile eşit sayılabilir, identical() ile sayılamaz. Bu, ileri bir detay — şimdilik identical()'ın gerçek bellek adresini kontrol ettiğini, =='nin ise class'ın tanımladığı eşitlik mantığını kullandığını bilmen yeterli.


🎯 Bu Dersten Çıkarılması Gerekenler

  • Garbage collection, artık kullanılmayan nesnelerin belleğini otomatik olarak geri kazanan bir mekanizmadır; Dart'ta elle bellek yönetimi gerekmez.
  • Dart'ın GC'si "generational"dır — kısa ömürlü nesneler (young generation) sık ve hızlı, uzun ömürlü nesneler (old generation) daha seyrek taranır; bu, UI-dostu performans sağlar.
  • const nesneler, aynı değerlere sahip olduklarında tek bir bellek konumunu paylaşır (identical() ile doğrulanabilir) — bu, daha az bellek kullanımı ve daha az GC yükü sağlar.
  • Flutter'da const widget'lar, gereksiz yeniden oluşturmadan (rebuild) tamamen kaçınılmasını sağlayarak doğrudan performans katkısı sunar.
  • Değişmezlik (immutability), paylaşılabilirlik sayesinde bellek verimliliğine katkıda bulunan genel bir prensiptir.

📝 Ödevler

  • [ ] const bir constructor'lı bir sınıf yaz, aynı değerlerle iki const nesne oluştur, identical() ile aynı bellek adresini paylaştıklarını kanıtla.
  • [ ] Aynı sınıfı const olmadan iki kere oluştur, identical() ile bu sefer farklı nesneler olduklarını göster.
  • [ ] Kendi cümlelerinle, "neden const nesneler paylaşılabilir ama normal nesneler paylaşılamaz" sorusunu, değişmezlik kavramıyla ilişkilendirerek açıkla.
  • [ ] Generational garbage collection'ın "young generation" ve "old generation" ayrımını, kendi örneğinle (örn. bir döngü içinde oluşturulan geçici değişkenler vs uygulamanın ana state'i) açıkla.
  • [ ] Kendi cümlelerinle, "Flutter'da const widget kullanmanın performans üzerindeki etkisi nedir" sorusunu, bu derste öğrendiğin bellek modeliyle bağlantı kurarak yanıtla.

Sıradaki konu: Bölüm 13 — Konu 63: Isolate'ler Arası Mesajlaşmanın Maliyeti ve compute() Fonksiyonunun İç İşleyişi