Performans ve Bellek Yönetimi Terimler Sözlüğü
Performance & Memory Management Glossary
Bu bölümde ki terimleri ezberlemenize gerek yoktur.
Konular içerisinde ki terimlerdir, sadece
konuyu daha iyi anlamanıza yardımcı olması
için eklenmiştir.
İlkel değerlerin ve fonksiyon çağrılarının depolandığı hızlı ve sıralı bellek bölgesi. LIFO (Last-In, First-Out) prensibiyle çalışır.
Nesnelerin, dizilerin ve fonksiyonların depolandığı dinamik ve rastgele erişimli bellek bölgesi. Çöp Toplayıcı (GC) tarafından yönetilir.
Artık kullanılmayan bellek bloklarını otomatik olarak tespit edip serbest bırakan mekanizma. JavaScript'te Mark and Sweep algoritması kullanılır.
Artık kullanılmayan bellek alanlarının serbest bırakılmaması durumu. GC'nin nesneyi "erişilebilir" olarak algılaması nedeniyle oluşur.
Nesnelere zayıf referanslarla meta veri eklemek için kullanılan veri yapısı. GC'ye dosttur ve bellek sızıntılarını önler.
Nesnelerin üyeliğini zayıf referanslarla takip eden veri yapısı. GC nesneyi topladığında otomatik olarak silinir.
Ana iş parçacığını bloke etmeden CPU yoğun görevleri çalıştırmak için kullanılan arka plan iş parçacığı mekanizması.
Her nesnenin referans sayısını tutan eski GC algoritması. Döngüsel referans sorunu nedeniyle modern tarayıcılarda kullanılmaz.
Modern JavaScript motorlarının kullandığı GC algoritması. Köklerden başlayarak erişilebilir nesneleri işaretler, işaretlenmemiş olanları temizler.
Nesnelerin çoğunun kısa ömürlü olduğu gözlemine dayanan optimizasyon. Heap'i Yeni Nesil ve Eski Nesil olarak ayırır.
Çöp toplama işini birden fazla CPU çekirdeğinde paralel olarak çalıştıran optimizasyon. Duraklama süresini azaltır.
Çöp toplama işinin bazı kısımlarını program çalışırken arka planda çalıştıran optimizasyon. UI'ı bloke etmez.
Bir nesnenin kendi boyutu ve canlı tuttuğu tüm bağımlı nesnelerin toplam bellek miktarı. Bellek sızıntısı analizinde kritik metrik.
Bellekte yeni bir nesne için yer ayırma işlemi. new Object() veya [] gibi
işlemler tahsis oluşturur.
Uygulamanın performansını ölçmek için kullanılan tarayıcı API'si. performance.now() ve
performance.memory gibi metodlar sağlar.
Uygulamanın bellek durumunun belirli bir andaki fotoğrafik kopyası. Bellek sızıntılarını tespit etmek için Chrome DevTools'ta kullanılır.
Bellek tahsislerinin zaman çizelgesi üzerinde kronolojik kaydını tutan Chrome DevTools özelliği. Hangi fonksiyonun ne zaman bellek kullandığını gösterir.
Ana iş parçacığını 50 milisaniyeden daha uzun süre bloke eden görevler. UI takılmalarına (jank) neden olur.
Saniyede gösterilen kare sayısı. Akıcı bir kullanıcı deneyimi için 60 FPS hedefi önemlidir.
Tarayıcının elementlerin boyut ve konumlarını yeniden hesaplaması. Performans açısından maliyetli bir işlemdir.
Tarayıcının elementlerin görsel özelliklerini (renk, arka plan) yeniden çizmesi. Reflow'dan daha az maliyetlidir.
Bir fonksiyonun, tanımlandığı leksikal kapsamdaki değişkenlere erişmesi. Bellek sızıntılarına neden olabilir.
window veya global nesnesine ait değişkenler. GC kökleri olarak kabul
edilir
ve
bellek sızıntılarına neden olabilir.
setTimeout ve setInterval ile oluşturulan zamanlayıcılar. Temizlenmezse
bellek
sızıntılarına neden olur.
Belirli bir olay gerçekleştiğinde çalıştırılan fonksiyon. Kaldırılmazsa bellek sızıntılarına neden olur.
Worker'a kopyalanmadan sahipliği transfer edilebilen nesneler. ArrayBuffer gibi. Büyük
veri setleri için performans kazancı sağlar.
postMessage ile Worker'a veri gönderirken kullanılan kopyalama algoritması. Veri
güvenliğini
sağlar ancak maliyetlidir.
Tarayıcıda UI'ı güncelleyen, olayları işleyen ve kodları yürüten tek iş parçacığı. Bloke edilirse UI donar.
GC çalışırken tüm programın donması durumu. Modern optimizasyonlarla (Paralel, Eşzamanlı GC) azaltılmaya çalışılır.
GC köklerinden (Global, Stack) doğrudan veya dolaylı olarak ulaşılabilen nesneler. GC tarafından toplanmaz.
GC'nin başlangıç noktaları. Global nesne, aktif fonksiyonların Stack'i ve aktif olay dinleyicileri köklerdir.
number, string, boolean, null,
undefined
gibi sabit boyutlu değer tipleri. Stack'te depolanır.
Object, Array, Function gibi dinamik boyutlu nesneler.
Heap'te
depolanır ve referans olarak kopyalanır.
İlkel değerlerin değiştirilemez olması özelliği. Değer kopyalandığında orijinal değer korunur.
Nesnelerin değiştirilebilir olması özelliği. Referans kopyalandığında aynı nesneye işaret eder.
'use strict'; direktifi ile etkinleştirilen mod. Kasıtsız global değişkenleri önleyerek
bellek sızıntılarını engeller.
Aynı bellek bloğunu birden fazla kez serbest bırakmaya çalışma hatası. Manuel bellek yönetiminde görülür, JavaScript'te GC tarafından önlenir.
Bellek serbest bırakıldıktan sonra hala o adrese referans veren değişken. Manuel bellek yönetiminde görülür, JavaScript'te GC tarafından önlenir.
İki veya daha fazla nesnenin birbirine karşılıklı olarak referans vermesi. Reference Counting algoritmasının çözemediği sorundur.
Generational GC'de yeni oluşturulan nesnelerin yerleştirildiği Heap bölgesi. Sık ve hızlı taranır (Minor GC).
Generational GC'de uzun ömürlü nesnelerin yerleştirildiği Heap bölgesi. Daha az sıklıkta ancak kapsamlı taranır (Major GC).
Hangi fonksiyonun, hangi milisaniyede ve ne kadar bellek tahsisi yaparak GC'yi gereksiz yere zorladığını gösteren metrik.
Performans Optimizasyon ( Ana Konu Giriş )
Bu ana bölümde, otomatik bellek yönetiminin (GC) karşılaştığı pratik zorlukları ve bu zorluklara karşı geliştirilmiş mühendislik çözümlerini ele alacağız. Kodumuzun UI'ı dondurmasını önleyen paralel işlem (Web Workers) tekniklerinden, uygulamanın uzun vadeli kararlılığını sağlamak için kritik öneme sahip bellek sızıntılarını ve referans yönetimini optimize eden ileri seviye algoritmalara odaklanacağız.
Çöp Toplama (GC) Algoritmalar ve Verimlilik Mekanikleri
Çöp Toplama (GC), bir programın artık ihtiyaç duymadığı bellek bloklarını otomatik olarak tespit eden ve bu alanları sisteme geri kazandıran hayati bir motor mekanizmasıdır.
JavaScript geliştiricileri, düşük seviyeli dillerde (C/C++ gibi) olduğu gibi belleği manuel olarak tahsis etmek allocate veya boşaltmak free zorunda değildir.
Bu otonom yapı, geliştiriciyi "Bellek Sızıntısı" ve çökme risklerinden koruyarak kod güvenliğini artırır.
Heap (Öbek) ve Referans Tiplerinin YönetimiGC Mekanizması: özellikle boyutu dinamik olarak değişen ve yaşam süresi önceden kestirilemeyen "Heap" üzerindeki nesneleri yönetmek için tasarlanmıştır.
İlkel tipler yığın üzerinde daha basit bir kuralla yönetilirken; nesneler, diziler ve fonksiyonlar gibi referans tipleri Heap üzerinde saklanır ve GC'nin radarındadır.
Felsefi Temel: Erişilebilirlik (Reachability)JavaScript Motoru: Bir nesnenin silinip silinmeyeceğine "Erişilebilirlik" kuralına göre karar verir.
Eğer bir nesneye köklere ( Global değişkenler , aktif fonksiyonların yerel değişkenleri vb. ) başlayarak bir referans zinciri ile ulaşılabiliyorsa, o nesne canlı kabul edilir.
Erişilemez hale gelen, yani hiçbir referans bağı kalmayan nesneler "çöp" olarak işaretlenir ve ilk GC döngüsünde bellekten atılır.
GC her ne kadar hayat kurtaran bir yardımcı olsa da, "Stop-the-World" (Dünyayı Durdur) denilen bir maliyete sahiptir.
Toplama işlemi yapılırken JavaScript yürütmesi çok kısa bir anlığına duraklayabilir.
Bu nedenle, performans optimizasyonu yapan bir mimar için GC'nin nasıl çalıştığını anlamak, sadece kod yazmak değil,
"akıcı bir kullanıcı deneyimi" tasarlamak anlamına gelir.
Çöp Toplama Algoritmaları Verimlilik Mekanikleri
Mark-and-Sweep: JavaScript motorlarının çoğunda kullanılan en temel ve etkili algoritmadır.
Bu algoritma, sadece referans sayısına bakmak yerine "erişilebilirliğe" odaklanır.
Süreç iki aşamadan oluşur: Motor önce "köklerden" ( window , global , aktif yerel global, aktif yerel değişkenler gibi) başlayarak ulaşılabilen her nesneyi işaretle.
Ardından, üzerinde hiçbir işaret bulunmayan, yani köklerden kopmuş nesneleri bellekten Sweep yapar yani süpürür.
Üretimsel Hipotez (Generational Hypothesis)Bellek yönetimini hızlandırmak için kullanılan en zekice tekniklerden biri Üretimsel Hipotez'dir.
Bu gözlem, yazılım dünyasında "nesnelerin çoğunun yaratıldıktan hemen sonra işlevini yitirip öldüğü" gerçeğine dayanır.
Genç ve Yaşlı Nesneler: Heap belleği ikiye ayrılır: Young Generation (Genç Nesil) ve Old Generation (Yaşlı Nesil). Yeni yaratılan nesneler önce genç bölüme alınır ve burada çok hızlı temizlenir.
Eğer bir nesne birkaç temizlik döngüsünden sağ çıkmayı başarırsa, "yaşlı" kabul edilerek daha seyrek temizlenen yaşlı bölüme terfi ettirilir.
Bu ayrım, her seferinde tüm belleği tarama yükünü ortadan kaldırır.
Stop-the-World Problemi ve Artımlı ToplamaGC işlemleri doğası gereği ağır işlerdir.
Temizlik sırasında ana programın yürütülmesi anlık olarak durdurulur; buna "Stop-the-World" (Dünyayı Durdur) denir.
Eğer bu duraklama uzun sürerse, kullanıcı arayüzünde takılmalar oluşur.
Artımlı ve Paralel Çözümler: Modern V8 motoru gibi yapılar, bu duraklamaları minimize etmek için Incremental toplama yapar.
Yani devasa bir temizlik işini tek seferde yapmak yerine küçük parçalara böler ve ana kodun arasına serpiştirir.
Böylece uygulama akıcılığı korunmuş olur.
Çöp Toplama algoritmaları: belleği temiz tutmak ile programı takılmadan yürütmek arasındaki hassas dengeyi kuran mühendislik harikalarıdır.
Bu mekanizmaları anlamak, büyük veri setleriyle çalışan uygulamalarda neden bazı yapıların belleği "yorduğunu" kavramamızı sağlar.
Neden Otomatik Çöp Toplama? Manuel Bellek Yönetimi Riskleri
Manuel Bellek Yönetimi (C veya C++ gibi dillerde malloc/free ile yapılan), geliştiricinin bellekteki her bir baytın yaşam döngüsünden bizzat sorumlu olduğu bir sistemdir.
Ancak yazılımın karmaşıklığı arttıkça, belleği doğru zamanda serbest bırakmak insan zihninin hata payını aşan bir yük haline gelir.
"Otomatik Çöp Toplama", bu yükü yazılımcının omuzlarından alarak sistemi üç temel ve yıkıcı riskten korumak için geliştirilmiştir.
1. Bellek Sızıntıları (Memory Leaks)Görünmez Tüketim: Manuel yönetimde bir veri için bellek ayrıldığında, iş bittikten sonra bu alanın açıkça serbest bırakılması unutulursa, o bellek bloğu uygulama kapanana kadar "işgal edilmiş" olarak kalır.
Bu durum, uygulamanın zamanla yavaşlamasına ve en sonunda sistem kaynaklarının tükenerek uygulamanın çökmesine yol açar.
2. Boştaki Gösterici (Dangling Pointers)Geçersiz Referans: Bir bellek bloğu serbest bırakıldıktan sonra, program hala o adrese erişmeye çalışırsa ortaya çıkan durumdur.
Bu, sadece uygulamanın çökmesine değil, belleğin başka bir bölümündeki rastgele verilerin bozulmasına neden olur. Bu durum, yazılım tarihindeki en büyük "güvenlik açıklarının" ve "Sistem Hatası" (Segmentation Fault) uyarılarının temel kaynağıdır.
3. Çift Serbest Bırakma (Double Free)Veri Yapısı Bozulması: Zaten serbest bırakılmış bir bellek bloğunun yanlışlıkla tekrar serbest bırakılmaya çalışılmasıdır.
Bu, bellek yönetim biriminin iç yapısını bozar ve sistemin kararsız hale gelmesine neden olur.
Felsefi Sonuç: Geliştirici Odaklılığı ve Güvenlikİş Mantığına Dönüş: Otomatik Çöp Toplama'nın felsefesi, geliştiriciyi düşük seviyeli adres manipülasyonu labirentinden çıkarıp doğrudan
"Kullanıcı Değeri ve İş Mantığına" odaklamaktır.
JavaScript motoru, bellek adreslerini birer kara kutu olarak yöneterek geliştiricinin bu kritik hataları yapma ihtimalini ortadan kaldırır.
Otomatik GC: yazılımın "Stabilite ve Güvenlik" temellerini atan, insan hatasını minimize eden ve modern web'in yüksek performanslı yapısını mümkün kılan görünmez bir mühendislik kalkanıdır.
|
Hata Türü
|
Tanım ve Derinlemesine Açıklama
|
Kritik Sonuç ve Risk
|
|---|---|---|
|
Unutulmuş Serbest Bırakma
(Memory Leaks / Bellek Sızıntısı) |
Programın, artık erişilemeyen veya kullanılmayan bellek
alanını serbest bırakmayı
unutmasıdır.
Bu durum, çöp toplayıcının nesneyi yanlışlıkla "hala erişilebilir" olarak işaretlemesi nedeniyle oluşur. |
Uygulamanın zamanla daha fazla RAM tüketmesine, sistemin
yavaşlamasına ve uzun vadede
uygulamanın
kaynak tükenmesi nedeniyle çökmesine yol açan en yaygın hatadır.
|
|
İki Kere Serbest Bırakma
(Double Free) |
Aynı bellek bloğunu, program yaşam döngüsü içinde birden
fazla kez serbest bırakmaya
çalışmaktır.
|
Bellek yönetim sisteminin yapısını bozar, programın
çökmesine ve belleğin tutarsız bir
duruma
girmesine neden olur.
Bu durum, siber güvenlikte bilinen güvenlik açıklarına zemin hazırlayabilir. |
|
Sarkan İşaretçi
(Dangling Pointer) |
Bellek serbest bırakıldıktan sonra, bir değişkenin hala o
serbest bırakılmış bellek adresine
referans vermeye devam etmesidir.
|
Programın o adresteki veriyi okumaya veya yazmaya
çalışması,
öngörülemeyen davranışlara,
hatalı
verilere ( çünkü adres başka bir amaç için tahsis edilmiş
olabilir ) ve potansiyel güvenlik
açıklarına neden olur.
|
Referans Sayma (Reference Counting) Genel Bilgi
Referans Sayma, Çöp Toplama tarihindeki en basit ve anlaşılır yaklaşımdır ve bu yaklaşımın temel mantığı İlgi Düzeyini Ölçmektir.
Temel Felsefesi: Bir nesneye ihtiyaç duyulup duyulmadığını, ona işaret edenlerin sayısına bakarak anlamaktır.
Her nesne, arka planda kendisine kaç farklı değişkenin veya nesne özelliğinin bağlı olduğunu tutan gizli bir referans sayacına sahiptir.
Nasıl Çalışır? Sayaç Mekanizmasıİşleyiş oldukça matematiktir: Bir nesneye yeni bir referans atandığında ( bir değişkene atama yapıldığında ) sayaç artırılır.
O referans kaldırıldığında veya değişkenin kapsamı bittiğinde sayaç azaltılır.
Sayaç tam olarak sıfıra ulaştığında, motor bu nesnenin artık dünya ile hiçbir bağı kalmadığına hükmeder ve belleği anında serbest bırakır.
Anlık Temizlik: Bu yöntemin en büyük avantajı deterministik olmasıdır; yani nesne, referansı bittiği saniyede silinir.
"Stop-the-World" duraklamalarına neden olan devasa temizlik döngülerini beklemez.
Yıkıcı Kusur: Döngüsel Referanslar (Circular References)Algoritmanın terk edilmesine neden olan en büyük sorun, nesnelerin birbirine karşılıklı olarak kilitlenmesidir.
Eğer "Nesne A", "Nesne B"'ye işaret ediyor ve aynı zamanda "Nesne B" de "Nesne A"'ya işaret ediyorsa, her ikisinin de sayacı en az "1" olarak kalır.
Mantıksal Çıkmaz: Program bu nesneleri artık kullanmasa bile, sayaçlar asla sıfıra düşmediği için GC bu nesnelere dokunamaz.
Bu durum, bellekte temizlenemeyen "hayalet adalar" yaratarak ciddi "Bellek Sızıntılarına" yol açar.
Sonuç: Modern Motorların TercihiBu temel kusur nedeniyle, modern JavaScript motorları Referans Sayma algoritmasını ana temizlik mekanizması olarak kullanmayı bırakmıştır.
Bunun yerine, döngüsel referansları bile başarıyla yakalayabilen "Mark-and-Sweep" yöntemine geçiş yapılmıştır.
İşaretle ve Süpür (Mark and Sweep) Genel Bilgi
İşaretle ve Süpür, günümüz JavaScript ekosisteminin en güvenilir çöp toplama algoritmasıdır.
Bu algoritmanın başarısı, nesnelerin kaç kez referans edildiğine değil, "programın köklerinden bu nesneye hala ulaşılabiliyor mu?" sorusuna odaklanmasından gelir.
Bu yaklaşım, Referans Sayma'nın çözemediği döngüsel referans sorununu mimari olarak ortadan kaldırır.
1. Aşama: İşaretleme (Marking Phase)Köklerden Başlama (Roots): Süreç, "Roots" adı verilen ve programın her zaman erişebileceği başlangıç noktalarından başlar.
Çöp toplayıcı, bu köklerden bir ağ gibi dallanarak ulaştığı her nesneyi "canlı" olarak işaretler.
Rekürsif Tarama: Eğer bir nesne canlıysa, onun işaret ettiği diğer nesneler de taranır.
Bu zincirleme işlem, tüm bellek haritası taranana kadar devam eder. İşaretlenmiş bir nesne, programın hayati bir parçası olduğunu kanıtlamış demektir.
2. Aşama: Süpürme (Sweeping Phase)Hücre Temizliği: İşaretleme bittikten sonra motor, Heap belleğindeki tüm alanları tarar.
Üzerinde "canlı" işareti bulunmayan nesneler, köklerden kopmuş kabul edilir. Artık bu nesnelerin birbirini referans etmesi bir anlam ifade etmez; çünkü ana programa bağlı değillerdir.
Döngüsel Sorunun Çözümü: İki nesne birbirini gösterse bile ( A ↔ B ), eğer ikisine de Global veya Stack üzerinden bir erişim yolu yoksa, işaretleme aşamasında ikisi de atlanır ve süpürme aşamasında bellekten silinirler.İşaretle ve Süpür algoritması sayesinde JavaScript, geliştiricinin hata yapma ihtimaline karşı devasa bir güvenlik ağı sunar.
Bellek yönetimi artık sadece referans takibi değil, sistemin bütününe olan bağın dinamik bir denetimidir.
Modern GC Optimizasyonlarına Giriş Genel Bilgi
Stop-the-World (Dünyayı Durdur), geleneksel çöp toplama süreçlerinde GC çalışmaya başladığında tüm programın yürütülmesinin anlık olarak askıya alınması durumudur.
JavaScript motoru, bellekteki nesnelerin yerini değiştirirken veya onları silerken veri tutarsızlığını önlemek için yürütmeyi durdurmak zorundadır.
Ancak bu duraklamalar, modern web uygulamalarında kullanıcı arayüzünün donmasına ve "jank" denilen takılmalara yol açar.
60 FPS Hedefi ve Ana İş Parçacığı (Main Thread)JavaScript, doğası gereği tek bir Ana İş Parçacığı üzerinde çalışır.
Bu iş parçacığı hem kullanıcı etkileşimlerini ( tıklama , kaydırma ) yönetir hem de animasyonları işler.
Akıcı bir kullanıcı deneyimi için her karenin yaklaşık 16ms içinde tamamlanması gerekir.
Eğer GC süreci bu süreyi aşan bir duraklama yaratırsa, kullanıcı takılmaları hisseder.
Modern motorlar ( V8'in Orinoco projesi gibi ), bu maliyeti azaltmak için gelişmiş stratejiler geliştirmiştir.
Gelişmiş Stratejiler: Paralel ve Arka Plan YönetimiÇok çekirdekli işlemcilerin gücünden yararlanan modern motorlar, GC görevlerini artık sadece ana iş parçacığına hapsetmezler:
Paralel GC: Ana iş parçacığı durduğunda, iş yükü diğer yardımcı iş parçacıklarına bölünerek işlem süresi radikal şekilde kısaltılır.
Arka Plan (Concurrent) GC: Ana iş parçacığı JavaScript kodunu çalıştırmaya devam ederken, yardımcı iş parçacıkları arka planda sessizce "çöp" olabilecek nesneleri tarar ve işaretler.
Günümüzde GC, yalnızca bir "bellek temizlik görevlisi" değil, uygulamanın performans hedeflerine ulaşmasını sağlayan stratejik bir orkestra şefidir.
Motorların bu akıllı davranışları, karmaşık JavaScript uygulamalarının masaüstü yazılımları kadar akıcı ve tepkisel çalışabilmesinin temel sebebidir.
Üretimsel Çöp Toplama Generational Garbage Collection
Üretimsel Çöp Toplama, bellek yönetimini rastgele bir süreç olmaktan çıkarıp istatistiksel bir gözleme dayandırır.
"Üretimsel Hipotez" olarak bilinen bu gözlem iki ana gerçeği vurgular:
Yazılımda oluşturulan nesnelerin büyük çoğunluğu çok kısa ömürlüdür ( geçici değişkenler, kısa süreli fonksiyonlar).
Eğer bir nesne ilk birkaç temizlik döngüsünden sağ çıkabildiyse, muhtemelen çok daha uzun süre yaşamaya devam edecektir.
Yeni Nesil (Young Generation) ve Minor GCHızlı ve Çevik Temizlik: Yeni oluşturulan tüm nesneler önce "Yeni Nesil" adı verilen, genellikle küçük boyutlu bir bellek alanına yerleştirilir.
Bu alan çok sık aralıklarla taranır; buna Minor GC denir.
Alan küçük olduğu için tarama işlemi milisaniyeler sürer ve uygulama akıcılığını bozmaz.
Kısa ömürlü "çöp" nesneler daha sistemin geneline yayılmadan burada yakalanıp yok edilir.
Terfi Mekanizması: Eğer bir nesne, Yeni Nesil içindeki birkaç Minor GC döngüsünden başarıyla sağ çıkarsa ( hala erişilebilir durumdaysa ), artık "olgun" kabul edilir ve Eski Nesil bölümüne "terfi ettirilir".
Eski Nesil (Old Generation) ve Major GCDerinlemesine Temizlik: Eski Nesil, uygulamanın çekirdek verilerini ve uzun süreli hayatta kalan nesnelerini barındıran daha geniş bir alandır.
Buradaki nesnelerin ömrü daha uzun olduğu varsayıldığı için, tarama işlemi çok daha seyrek yapılır.
Maliyet Yönetimi: Major GC işlemi tüm alanı taradığı için daha maliyetlidir ve daha uzun duraklamalara neden olabilir.
Ancak Üretimsel Hipotez sayesinde, bu ağır tarama sadece gerçekten ihtiyaç duyulduğunda yapılarak sistem kaynaklarının verimli kullanılması sağlanır.
Üretimsel Çöp Toplama; belleği tek bir büyük havuz yerine iki farklı dinamikteki alana bölerek, performans ve kararlılık arasında mükemmel bir denge kurar.
Bu strateji sayesinde modern JavaScript motorları, binlerce nesne saniyeler içinde yaratılıp yok edilse bile sarsılmadan çalışmaya devam edebilir.
Paralel ve Eşzamanlı Toplama Çoklu İş Parçacığı Kullanımı
Paralel ve Eşzamanlı Toplama, JavaScript'in geleneksel "tek iş parçacıklı" kısıtlamasını aşarak, donanımın sunduğu çok çekirdekli işlemci gücünü bellek yönetimine dahil eder.
Bu stratejilerin ana hedefi, kullanıcıyı rahatsız eden "Stop-the-World" duraklamalarını milisaniyeler seviyesine indirmek ve uygulamanın tepki verme hızını korumaktır.
1. Paralel GC (Parallel GC): Güç Birliğiİş Bölümü: Paralel GC'de, ana program durdurulduğunda, çöp toplama görevi tek bir iş parçacığı yerine birden fazla yardımcı iş parçacığına dağıtılır.
Dramatik Hızlanma: Bir odayı tek kişinin temizlemesi yerine dört kişinin aynı anda temizlemesi gibi, toplam duraklama süresi çekirdek sayısına paralel olarak kısalır.
Bu, özellikle devasa veri setlerine sahip uygulamalarda Gecikme Süresini minimize eden kritik bir mekanizmadir.
2. Eşzamanlı GC (Concurrent GC): Arka Plan OperasyonuBloke Etmeyen Temizlik: Eşzamanlı GC'de, çöp toplama işleminin en maliyetli kısımları ( özellikle nesne işaretleme fazı ), ana iş parçacığı JavaScript kodunu çalıştırmaya devam ederken arka planda yürütülür.
Sıfıra Yakın Duraklama: Ana iş parçacığı, arka plandaki bu tarama bitene kadar işine devam eder.
Sadece sürecin sonunda, son bir kontrol ve temizlik için çok kısa bir süreliğine duraklar.
Bu sayede kullanıcı, 100 MB'lık bir bellek temizliği yapılırken bile arayüzde hiçbir takılma hissetmez.
Sonuç olarak modern motorlar, bu iki tekniği birleştirerek hibrit bir yapı kullanır.
Paralel toplama iş gücünü artırırken, eşzamanlı toplama bu gücü zamana yayarak ana iş parçacığını özgür bırakır.
Bu mimari zeka, JavaScript'in günümüzde yüksek performanslı oyunlardan, karmaşık veri görselleştirme araçlarına kadar her alanda kusursuz çalışmasının anahtarıdır.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>GC Simülatörü: Erişilebilirlik Testi Örneği</title>
<link rel="stylesheet" href="gc-visualizer.css?v=1.0.150">
</head>
<body>
<div class="gc-container">
<div class="gc-header">
<h3>GC Simülatörü: Erişilebilirlik Testi</h3>
<p>Aşağıdaki nesne "Global Root" üzerinden referans almaktadır. Referansı kopardığınızda GC'nin nesneyi
nasıl
"çöp" olarak işaretlediğini görün.</p>
</div>
<div class="gc-visual-area">
<div id="root-node" class="node root">Global Root (Window)</div>
<div id="connector" class="connector"></div>
<div id="object-node" class="node object">Veri Nesnesi (Heap)</div>
</div>
<div class="gc-controls">
<button onclick="breakReference()" id="break-btn">Referansı Kopar</button>
<button onclick="resetSimulation()" id="reset-btn" style="display:none;">Sistemi Sıfırla</button>
</div>
<div id="status-msg" class="status-msg">Durum: Nesne erişilebilir ve bellekte tutuluyor.</div>
</div>
<script src="gc-visualizer.js?v=1.0.150"></script>
</body>
</html>
/* Modern CSS Tasarımı */
.gc-container {
background: #f8f9fa;
border-radius: 12px;
padding: 25px;
border: 1px solid #e0e0e0;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
max-width: 600px;
margin: 20px auto;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.05);
}
.gc-header h3 {
color: #2c3e50;
margin-top: 0;
}
.gc-visual-area {
display: flex;
flex-direction: column;
align-items: center;
padding: 30px;
background: #ffffff;
border-radius: 8px;
margin-bottom: 20px;
}
.node {
padding: 15px 25px;
border-radius: 6px;
font-weight: bold;
transition: all 0.5s ease;
}
.root {
background: #3498db;
color: white;
border: 2px solid #2980b9;
}
.object {
background: #2ecc71;
color: white;
border: 2px solid #27ae60;
}
.connector {
width: 2px;
height: 40px;
background: #bdc3c7;
transition: all 0.5s ease;
}
.gc-controls {
text-align: center;
}
button {
padding: 10px 20px;
border: none;
border-radius: 5px;
cursor: pointer;
font-weight: 600;
transition: 0.3s;
}
#break-btn {
background: #e74c3c;
color: white;
}
#break-btn:hover {
background: #c0392b;
}
#reset-btn {
background: #34495e;
color: white;
}
.status-msg {
margin-top: 15px;
text-align: center;
font-size: 0.9em;
color: #7f8c8d;
font-style: italic;
}
/* GC Efekti */
.is-garbage {
background: #dcdde1 !important;
border-color: #7f8c8d !important;
color: #7f8c8d !important;
text-decoration: line-through;
transform: scale(0.9);
opacity: 0.5;
}
.connector.broken {
height: 0;
opacity: 0;
}
function breakReference() {
// Görsel değişimler
document.getElementById("connector").classList.add("broken");
const obj = document.getElementById("object-node");
obj.classList.add("is-garbage");
obj.innerText = "Çöp (Erişilemez)";
document.getElementById("status-msg").innerText =
"Durum: Referans koptu. Mark-and-Sweep algoritması bu nesneyi 'unreachable' (erişilemez) olarak işaretledi.";
document.getElementById("break-btn").style.display = "none";
document.getElementById("reset-btn").style.display = "inline-block";
}
function resetSimulation() {
document.getElementById("connector").classList.remove("broken");
const obj = document.getElementById("object-node");
obj.classList.remove("is-garbage");
obj.innerText = "Veri Nesnesi (Heap)";
document.getElementById("status-msg").innerText =
"Durum: Nesne yeniden bağlandı.";
document.getElementById("break-btn").style.display = "inline-block";
document.getElementById("reset-btn").style.display = "none";
}
Önemli Bilgilendirme
Bu laboratuvar, gerçek bir JavaScript motorunun çöp toplama mekanizmasını birebir çalıştırmaz.
Buradaki işlemler, Mark-and-Sweep ve Referans Sayma gibi algoritmaların temel mantığını öğretmek amacıyla eğitsel bir simülasyon olarak basitleştirilmiştir.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Byteomi GC Engine Lab</title>
<link rel="stylesheet" href="gc-lab-engine.css?v=1.0.150">
</head>
<body>
<div class="byteomi-lab-card">
<div class="lab-nav">
<h4>Byteomi GC Lab v1.0</h4>
<span id="status-log">Motor Beklemede...</span>
</div>
<div id="heap-visualizer" class="heap-grid">
</div>
<div class="lab-actions">
<button onclick="GCEngine.createObject('Yeni Veri')" class="btn-create">Nesne Ekle (Young)</button>
<button onclick="GCEngine.createCircular()" class="btn-warning">Döngüsel Referans (Hata)</button>
<button onclick="GCEngine.runMarkAndSweep()" class="btn-gc">GC'yi Çalıştır (Sweep)</button>
</div>
</div>
<script src="gc-lab-engine.js?v=1.0.150"></script>
</body>
</html>
.byteomi-lab-card {
border: 2px solid #34495e;
border-radius: 15px;
overflow: hidden;
background: #ecf0f1;
}
.lab-nav {
background: #34495e;
color: white;
padding: 10px 20px;
display: flex;
justify-content: space-between;
}
.heap-grid {
display: flex;
flex-wrap: wrap;
gap: 10px;
padding: 20px;
min-height: 150px;
}
.obj-card {
width: 100px;
height: 100px;
border-radius: 10px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: 12px;
text-align: center;
animation: popIn 0.3s ease;
}
.young {
background: #2ecc71;
color: white;
border: 3px solid #27ae60;
}
.old {
background: #f1c40f;
color: #2c3e50;
border: 3px solid #f39c12;
}
.btn-gc {
display: inline-flex;
align-items: center;
justify-content: center;
padding: 12px 18px;
font-size: 14px;
font-weight: 600;
color: #ecfeff;
background: linear-gradient(135deg, #22c55e, #16a34a);
border: none;
border-radius: 10px;
cursor: pointer;
box-shadow: 0 6px 15px rgba(34, 197, 94, 0.35);
transition:
transform 0.15s ease,
box-shadow 0.15s ease,
background 0.3s ease;
}
.btn-gc:hover {
transform: translateY(-2px);
box-shadow: 0 10px 25px rgba(34, 197, 94, 0.45);
}
.btn-gc:active {
transform: translateY(0);
box-shadow: 0 4px 10px rgba(34, 197, 94, 0.35);
}
.btn-warning {
display: inline-flex;
align-items: center;
justify-content: center;
padding: 12px 18px;
font-size: 14px;
font-weight: 600;
color: #fff;
background: linear-gradient(135deg, #f97316, #ef4444);
border: none;
border-radius: 10px;
cursor: pointer;
box-shadow: 0 6px 15px rgba(239, 68, 68, 0.35);
transition:
transform 0.15s ease,
box-shadow 0.15s ease,
background 0.3s ease;
}
.btn-warning:hover {
transform: translateY(-2px);
box-shadow: 0 10px 25px rgba(239, 68, 68, 0.45);
}
.btn-warning:active {
transform: translateY(0);
box-shadow: 0 4px 10px rgba(239, 68, 68, 0.35);
}
.btn-create {
display: inline-flex;
align-items: center;
justify-content: center;
padding: 12px 20px;
font-size: 15px;
font-weight: 600;
color: #ffffff;
background: linear-gradient(135deg, #38bdf8, #0ea5e9);
border: none;
border-radius: 10px;
cursor: pointer;
transition:
background 0.3s ease,
transform 0.15s ease,
box-shadow 0.15s ease;
box-shadow: 0 6px 15px rgba(14, 165, 233, 0.35);
}
.btn-create:hover {
transform: translateY(-2px);
box-shadow: 0 10px 25px rgba(14, 165, 233, 0.45);
}
.btn-create:active {
transform: translateY(0);
box-shadow: 0 4px 10px rgba(14, 165, 233, 0.35);
}
.btn-create:disabled {
background: #94a3b8;
cursor: not-allowed;
box-shadow: none;
transform: none;
}
@keyframes popIn {
from {
transform: scale(0);
}
to {
transform: scale(1);
}
}
// Byteomi GC Lab - Mimari Simülasyon Dosyası
class GCObject {
constructor(name, type = "young") {
this.name = name;
this.type = type; // 'young' veya 'old'
this.id = Math.random().toString(36).substr(2, 5);
this.references = 0;
}
}
const GCEngine = {
heap: [],
roots: ["Window", "GlobalStack"],
// Yeni nesne oluşturma (Üretimsel Hipotez Gereği 'Young' başlar)
createObject(name) {
const obj = new GCObject(name);
this.heap.push(obj);
this.updateUI();
},
// Referans Sayma Mantığı: Döngüsel Referans Hatası Simülasyonu
createCircular() {
const objA = new GCObject("Nesne A");
const objB = new GCObject("Nesne B");
// Birbirlerini işaret ediyorlar (Circular)
objA.refersTo = objB.id;
objB.refersTo = objA.id;
objA.references = 1;
objB.references = 1;
this.heap.push(objA, objB);
this.updateUI(
"Döngüsel referans oluştu! Referans sayma bu nesneleri silemez.",
);
},
// Mark and Sweep Simülasyonu
runMarkAndSweep() {
const status = document.getElementById("status-log");
status.innerText = "GC Başladı: Root'tan erişilemeyenler süpürülüyor...";
// Simülasyon gereği referansı 0 olanları temizle
this.heap = this.heap.filter((obj) => obj.references > 0);
setTimeout(() => {
this.updateUI(
"Mark-and-Sweep tamamlandı. Erişilemez nesneler bellekten atıldı.",
);
}, 800);
},
updateUI(msg = "Sistem Hazır") {
const container = document.getElementById("heap-visualizer");
container.innerHTML = "";
this.heap.forEach((obj) => {
const div = document.createElement("div");
div.className = `obj-card ${obj.type}`;
div.innerHTML = `<strong>${obj.name}</strong><br><small>Ref: ${obj.references}</small>`;
container.appendChild(div);
});
document.getElementById("status-log").innerText = msg;
},
};
Bellek Sızıntıları, Workers ve Zayıf Referans Çözümleri Performans Optimizasyon Ana Konu Detayı
Bellek Sızıntısı (Memory Leak), bir nesnenin mantıksal olarak işi bitmesine rağmen, kodun içinde unutulan bir referans nedeniyle "erişilebilir" kalması ve bu yüzden Çöp Toplayıcı tarafından silinememesi durumudur.
Bu sızıntılar, uygulamanın zamanla ağırlaşmasına, mobil cihazların ısınmasına ve sonunda tarayıcı sekmesinin çökmesine neden olur.
Geliştirici olarak görevimiz, GC teknik olarak "yanıltılmaz"; yalnızca erişilebilirlik kurallarını mekanik olarak uygular.
İşlemci Özgürlüğü: Web WorkersJavaScript'in tek iş parçacıklı yapısı, ağır hesaplamalar yapıldığında kullanıcı arayüzünün donmasına neden olur.
Web Workers, bu darboğazı aşmak için CPU yoğunluklu görevleri ( veri işleme, kompleks matematiksel modeller ) ana iş parçacığından ayırarak arka plana taşır.
Bu mimari ayrım, arayüzün her zaman tepkisel kalmasını sağlayarak kullanıcı deneyimini zirveye taşır.
Mimari Çözüm: Zayıf Referanslar (WeakMap & WeakSet)Bellek yönetiminde karşılaşılan en büyük zorluklardan biri, nesneleri bir anahtar olarak kullanırken onları istemeden belleğe hapsetmektir. WeakMap ve WeakSet, bu noktada devreye giren "zayıf referans" veri yapılarıdır.
GC Dostu Yapı: Klasik bir Map içine bir nesne koyduğunuzda, o nesneye başka hiçbir yerden ulaşılamasa bile Map içinde olduğu için silinmez.
Ancak bir WeakMap, nesnenin asıl referansı koptuğunda onun "çöp" olarak toplanmasına engel olmaz.
Bu, özellikle önbellekleme ve DOM elementlerine veri bağlama işlemlerinde sızıntıları kökten çözen mimari bir mucizedir.
Sonuç olarak performans optimizasyonu; sadece hızlı kod yazmak değil, belleği bilinçli yönetmek ve işlemci yükünü akıllıca dağıtmaktır.
Bellek sızıntılarını önleyen, Workers ile ana thread'i rahatlatan ve zayıf referanslarla GC'ye yol gösteren bir yapı, kurumsal seviyedeki uygulamaların başarısının anahtarıdır.
Bellek Sızıntıları (Memory Leaks) Tanım ve Yaygın Nedenler
Bellek Sızıntısı, teknik olarak bir nesnenin uygulama mantığı içinde işlevini tamamlamış olmasına rağmen, kodun içinde kalan bir referans bağı nedeniyle sistemden silinememesi durumudur.
Bu, bir otelde check-out yapmış bir müşterinin odasının anahtarının teslim edilmemesi ve bu yüzden odanın yeni misafirlere kapatılmasına benzer.
RAM üzerindeki bu alanlar "rehin" tutulur ve sistem kaynakları verimsizce tükenir.
Erişilebilirlik YanılsamasıKasıtsız Güçlü Referanslar: Çöp Toplama mekanizması, bir nesnenin "ihtiyaç duyulup duyulmadığını" anlayamaz; sadece
"erişilebilir olup olmadığını" denetleyebilir.
Geliştirici, artık kullanmadığı bir veriyi kazara global bir değişkene bağladığında veya bir olay dinleyicisi içinde unuttuğunda, GC'ye "bu veri hala canlı" mesajı gönderir, bu yanlış sinyal, belleğin temizlenmesini engeller.
Mimari ve Performans Üzerindeki EtkileriPerformans Erozyonu: Bellek sızıntıları genellikle anlık bir çökme yaratmaz; bunun yerine uygulamanın performansını zamanla, sinsi bir şekilde düşürür.
RAM kullanımı arttıkça, GC sistemi alanı boşaltmak için daha sık ve daha uzun süreli çalışmaya başlar.
Bu da kullanıcı arayüzünde takılmalara ve tepkisizliğe yol açar.
Kaynak Tüketimi: Özellikle uzun süre açık kalan tek sayfalı uygulamalarda, sızıntılar birikerek sistemin tüm boş belleğini yutabilir.
Bu durum, tarayıcının sekme bazlı güvenlik mekanizmasını tetikleyerek uygulamanın "Out of Memory" hatasıyla sonlanmasına neden olur.
Sonuç: Geliştiricinin Sorumluluk AlanıSonuç olarak bellek sızıntıları, JavaScript'in otomatik sistemlerinin bir hatası değil, kodun mimari kurgusundaki referans yönetimi eksikliğidir.
Profesyonel bir geliştirici, nesnelerin yaşam döngüsünü doğru yöneterek ve işi biten bağımlılıkları serbest bırakarak GC'ye işini yapması için doğru yolu göstermelidir.
Global Değişkenler Accidental Global Variables
JavaScript'in esnek yapısı, bazen en büyük zayıflığına dönüşebilir. Bir değişkene let, const veya var anahtar kelimelerini kullanmadan değer atandığında ( veri = [1, 2, 3]; gibi), JavaScript motoru bu değişkeni bulamaz ve otomatik olarak Global Nesneye bir özellik olarak ekler ve bu durum, değişkenin "kapsamsız" kalmasına ve uygulamanın en tepesine sızmasına neden olur.
GC ve Kök (Root) İlişkisiKalıcı Erişim: Çöp Toplayıcı algoritması için Global Nesne, asla yok edilemeyen ve her zaman canlı kabul edilen ana bir "Kök" noktasıdır.
Bu kök nesneye doğrudan bağlı olan her şey, GC tarafından "kesinlikle ihtiyaç duyuluyor" olarak algılanır.
Bellek Esareti: Kasıtsız olarak globale sızan büyük bir veri seti ( binlerce satırlık bir kullanıcı listesi gibi), fonksiyon çalışmasını bitirse dahi global nesneye bağlı kaldığı için bellekten asla silinemez.
Bu, uygulamanın RAM kullanımının sürekli artmasına yol açan en ilkel sızıntı türüdür.
Yaygın Hata: "this" Bağlamının KaymasıGlobal sızıntıların bir diğer gizli nedeni ise this anahtar kelimesidir.
Bir "Constructor" fonksiyonu ( function User() { ... } gibi ) çağrılırken new kelimesi unutulursa, fonksiyon içindeki this ifadesi global nesneyi işaret eder.
Bu hata, sınıfa ait olması gereken tüm verilerin doğrudan window nesnesine yazılmasına ve sistemin şişmesine neden olur.
Savunma Hattı: Sıkı Mod (Strict Mode)Mühendislik Çözümü: Bu tür sızıntıları önlemenin en profesyonel yolu, dosya veya fonksiyon başında 'use strict'; direktifini kullanmaktır.
Sıkı Mod, bildirimsiz değişken kullanımını bir hata ( ReferenceError ) olarak kabul eder ve sızıntı daha oluşmadan geliştiriciyi uyararak kodun güvenliğini sağlar.
Özet olarak Global Değişken sızıntıları, JavaScript'in "esnekliğini" kötüye kullanan mimari boşluklardır.
Değişkenlerin yaşam döngüsünü dar tutmak ve modern standartları takip etmek, belleğin bu sessiz istilacıdan korunmasını sağlar.
Unutulmuş Zamanlayıcılar ve Olay Dinleyicileri Genel Bilgi
Zamanlayıcılar (Timers) ve olay dinleyicileri, JavaScript'in asenkron doğasının temel taşlarıdır.
Ancak bu yapılar, doğası gereği "gecikmeli" veya "etkileşim bazlı" çalıştıkları için, işleri bittiğinde kendilerini otomatik olarak yok etmezler.
Eğer bir geliştirici bu bağları manuel olarak koparmazsa, GC bu yapıları hala "canlı ve gerekli" kabul eder.
1. Unutulmuş Zamanlayıcılar (Timers)Closure Tuzağı: setInterval veya setTimeout kullanıldığında, tarayıcı arka planda bir zamanlayıcı başlatır.
Bu zamanlayıcıya geçilen callback fonksiyonu, o anki kapsamındaki tüm değişkenlere bir referans tutar.
GC'yi Yanıltmak: Aktif bir zamanlayıcı, GC için geçici bir "Kök" görevi görür.
Zamanlayıcı clearInterval veya
clearTimeout ile durdurulmadığı sürece, içindeki fonksiyon ve o fonksiyonun eriştiği devasa
veri
setleri bellekte kilitli kalır.
Fonksiyonun bağlı olduğu ana bileşen yok olsa bile, zamanlayıcı çalışmaya devam ettiği sürece bellek serbest bırakılamaz.
2. Unutulmuş Olay Dinleyicileri (Event Listeners)DOM ve Bellek İlişkisi: Bir butona veya pencereye eklenen addEventListener, hem DOM elemanı hem de dinleyici fonksiyonu arasında güçlü bir bağ kurar.
Modern JavaScript motorları birçok durumu yönetebilse de, özellikle Tek Sayfa Uygulamalarında ciddi sızıntılar yaşanır.
Ayrık DOM Sızıntısı: Bir bileşen ekrandan kaldırıldığında, eğer ona bağlı olan scroll veya resize gibi global dinleyiciler removeEventListener ile temizlenmezse, o bileşene ait tüm kod ve veriler bellekte "hayalet" olarak yaşamaya devam eder ve eleman DOM'da yoktur ancak bellekten silinmesi engellenmiştir.
Savunma Stratejisi: Yaşam Döngüsü DisipliniMimari Çözüm: Bellek sızıntılarını önlemenin altın kuralı, bir yapıyı oluştururken onun nasıl yok edileceğini en baştan planlamaktır.
React'te useEffect'in dönüş fonksiyonu veya Angular'da ngOnDestroy metodu, bu temizlik işlemlerinin ( unsubscribe, removeEventListener, clearInterval ) yapılacağı güvenli limanlardır.
Sonuç olarak asenkron işlemler; gücü kadar sorumluluğu da beraberinde getirir.
Referans bağlarını manuel olarak yönetmek, uygulamanın zamanla ağırlaşmasını önleyen ve sistem kaynaklarını saygılı kullanan
üst düzey bir mühendislik yaklaşımıdır.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Worker Logic Lab</title>
<link rel="stylesheet" href="worker-logic.css?v=1.0.150">
</head>
<body>
<div class="lab-container">
<div class="lab-header">
<h3>Web Worker: CPU İzolasyon Testi</h3>
<p>Ağır bir hesaplama sırasında arayüzün (UI) donup donmadığını test edin.</p>
</div>
<div class="ui-visual">
<div class="bouncing-ball"></div>
<span>Arayüz Akıcılık Göstergesi (60 FPS)</span>
</div>
<div class="controls">
<button onclick="runMainThread()" class="btn-danger">Ana Thread'de Çalıştır (Donma Risk!)</button>
<button onclick="runWorkerThread()" class="btn-success">Worker'da Çalıştır (Akıcı)</button>
</div>
<div id="result-log" class="log">Durum: İşlem bekleniyor...</div>
</div>
<script src="worker-logic.js?v=1.0.150"></script>
</body>
</html>
.lab-container {
background: #1a1a1a;
color: #fff;
padding: 25px;
border-radius: 15px;
font-family: sans-serif;
}
.ui-visual {
background: #222;
height: 100px;
position: relative;
border-radius: 10px;
margin: 15px 0;
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
}
.bouncing-ball {
width: 30px;
height: 30px;
background: #00ff88;
border-radius: 50%;
position: absolute;
animation: move 2s infinite alternate ease-in-out;
}
@keyframes move {
from {
left: 10%;
}
to {
left: 80%;
}
}
.controls {
display: flex;
gap: 10px;
flex-wrap: wrap;
}
button {
padding: 12px;
border: none;
border-radius: 5px;
cursor: pointer;
font-weight: bold;
transition: 0.3s;
}
.btn-danger {
background: #ff4757;
color: white;
}
.btn-success {
background: #2ed573;
color: white;
}
.log {
margin-top: 15px;
padding: 10px;
background: #333;
border-left: 4px solid #00ff88;
font-size: 14px;
}
// Inline Worker Yaratma (Test için kolaylık sağlar)
const workerCode = `
onmessage = function(e) {
let count = 0;
for(let i=0; i<500000000; i++) { count += i; } // Ağır Hesaplama
postMessage('Hesaplama Tamamlandı: ' + count);
};
`;
const blob = new Blob([workerCode], { type: "application/javascript" });
const myWorker = new Worker(URL.createObjectURL(blob));
function runMainThread() {
document.getElementById("result-log").innerText =
"Ana Thread meşgul ediliyor... Top duracak!";
// UI'ı donduran işlem
setTimeout(() => {
let count = 0;
for (let i = 0; i < 500000000; i++) {
count += i;
}
document.getElementById("result-log").innerText =
"Bitti (Ana Thread)! Sonuç: " + count;
}, 100);
}
function runWorkerThread() {
document.getElementById("result-log").innerText =
"Worker arka planda çalışıyor... Top hareketine devam ediyor!";
myWorker.postMessage("start");
myWorker.onmessage ||= function (e) {
document.getElementById("result-log").innerText =
"Bitti (Worker)! " + e.data;
};
}
Kapanımlar (Closures) İçinde Gereksiz Referanslar Genel Bilgi
Closure (Kapanım), bir fonksiyonun kendi dışındaki kapsamda bulunan değişkenleri hatırlama ve onlara erişme yeteneğidir.
Bu özellik, JavaScript'te veri gizleme ve fonksiyonel programlama için devrimsel bir güç sunar. Ancak bu güç, bellek yönetimi söz konusu olduğunda bir "rehin alma" durumuna dönüşebilir.
Eğer bir closure, işi bitmiş devasa bir veri grubuna referans tutmaya devam ederse, o veri grubu asla bellekten silinemez.
Sızıntı Mekanizması: Bellekteki "Rehineler"Yaşam Süresi Çatışması: Bir sızıntı, genellikle uzun ömürlü bir yapının ( Global bir nesne veya kalıcı bir olay dinleyicisi gibi ) içine atanmış küçük bir fonksiyonun, aslında çoktan yok olması gereken büyük bir objeye erişmesiyle başlar.
Closure canlı kaldığı sürece, kapsamındaki her şeyi "erişilebilir" olarak işaretler ve Çöp Toplayıcının elini kolunu bağlar.
Gereksiz Kapsam Koruma: Closure, sadece ihtiyaç duyduğu değişkeni değil, teknik olarak bağlı olduğu tüm Leksikal Ortamı bellekte tutma eğilimindedir.
Bu, büyük bir veri kütlesinin, içindeki küçücük bir fonksiyon tarafından ömür boyu "rehin" tutulması gibidir.
Bellek Zinciri ve Mark-and-SweepDolaylı Bağlantı: GC'nin kullandığı Mark-and-Sweep algoritması, "Kökler → Kapanım → Büyük Veri" zincirini takip eder.
Köklerden kapanıma ulaşılabildiği sürece, kapanımın içindeki büyük obje de "canlı" sayılır.
Bu durum, birbirinden bağımsız görünen kod parçaları arasında görünmez bir Bellek Zinciri oluşturur.
Savunma Stratejisi: Referans Zincirini KırmakManuel Müdahale: Closure kaynaklı sızıntıları önlemek için, artık ihtiyaç duyulmayan ancak closure içinde referansı kalan büyük nesneleri açıkça null değerine eşitleyerek referans bağını koparmak gerekir.
Bu, GC'ye "artık bu nesneye giden yol kapandı" sinyalini vermenin en garantili yoludur.
Sonuç olarak closure'lar, neyi bellekte tuttuğunuzu tam olarak kontrol etmenizi gerektiren yapılardır.
Bellek verimli bir uygulama için, fonksiyonların hangi verileri "hatırladığını" analiz etmek ve gereksiz "rehineleri" serbest bırakmak profesyonel bir mühendislik disiplinidir.
Web Workers ile Paralel İşlem Çözüm 1
JavaScript, tarayıcı ortamında doğası gereği tek bir Ana İş Parçacığı (Main Thread) üzerinde çalışır.
Bu iş parçacığı; sayfanın render edilmesi, buton tıklamaları gibi kullanıcı etkileşimleri ve kod yürütme süreçlerinden sorumludur.
Eğer bu hat üzerinde 50ms'den uzun süren ağır bir hesaplama ( Büyük bir veri setinin filtrelenmesi veya karmaşık bir matematiksel modelin çözülmesi gibi ) yapılırsa, tarayıcı "donar" ve kullanıcı tepkisiz bir arayüzle karşılaşır.
Çözüm: Arka Plan İşçileri (Web Workers)İş Yükü İzolasyonu: Web Workers, JavaScript'e gerçek anlamda Çoklu İş Parçacığı (Multi-threading) yeteneği kazandırır.
Bu yapı sayesinde CPU yoğunluklu görevler, Ana İş Parçacığından tamamen bağımsız bir arka plan ortamına taşınır.
Worker kendi çekirdeğinde çalışırken, Ana İş Parçacığı kullanıcı etkileşimlerine yanıt vermeye ve animasyonları 60 FPS akıcılığında oynatmaya devam eder.
Mesajlaşma Tabanlı İletişim: Worker'lar ana koddan izole oldukları için doğrudan window veya DOM nesnelerine erişemezler. İletişim, güvenli bir "mesajlaşma" sistemi üzerinden yürütülür.
Bu, verinin arka planda işlenip sonuçların ana iş parçacığına bir "paket" olarak gönderilmesini sağlar.
Performans Avantajı: Kesintisiz DeneyimUI Garantisi: Web Workers kullanımı, uygulamanın sadece "hızlı" görünmesini değil, gerçekten tepkisel kalmasını garantiler.
Özellikle veri görselleştirme, video/ses işleme veya büyük JSON dosyalarının ayrıştırılması gibi durumlarda, Workers kullanımı mimari bir tercih değil, zorunluluktur.
Sonuç olarak Web Workers; JavaScript'in sınırlarını tarayıcı tabanlı basit script'lerden, masaüstü yazılım gücünde yüksek performanslı web uygulamalarına taşır.
İşlemci çekirdeklerini verimli dağıtmak, modern web mühendisliğinin en temel optimizasyon stratejisidir.
Mekanizma Arka Plan İş Parçacığı Yaratma
Web Workers, tarayıcı motoruna tek bir komutla tamamen bağımsız bir arka plan iş parçacığı oluşturma yeteneği tanır.
Bu, JavaScript'in "aynı anda sadece bir iş yapabilme" sınırlamasını donanımsal düzeyde aşar.
Ana iş parçacığı kullanıcıya pürüzsüz bir arayüz sunarken, oluşturulan bu ikincil iş parçacığı işlemcinin boşta kalan çekirdeklerini kullanarak ağır görevleri üstlenir.
Tam İzolasyon: Güvenlik ve KararlılıkErişim Kısıtlamaları: Worker'lar, "İzolasyon" prensibi gereği ana iş parçacığındaki değişkenlere, fonksiyonlara veya en önemlisi DOM yapısına doğrudan erişemezler.
Bu kısıtlama, yazılım dünyasında "tehlikeli" olarak kabul edilen ve hata ayıklaması en zor problemlerden olan Yarış Koşullarının ve bellek çakışmalarının doğal bir bariyerle önüne geçer.
Veri Güvenliği: İzolasyon sayesinde, arka plandaki bir hesaplama hatası veya sonsuz döngü, ana iş parçacığını ( dolayısıyla tüm web sayfasını ) çökertmez.
Her iki ortam da kendi bellek alanında güvenli bir şekilde çalışır.
Avantaj: CPU Yoğun Görevlerin YönetimiGecikmesiz Performans: Karmaşık algoritmalar ( Şifreleme işlemleri, büyük resim/video manipülasyonu ) veya yoğun matematiksel hesaplamalar arka plana aktarıldığında, Ana İş Parçacığı üzerindeki baskı tamamen kalkar.
Bu durum, tarayıcının saniyede 60 kare tazeleme hızını korumasını sağlayarak, en ağır işlemlerde bile kullanıcının akıcı bir deneyim yaşamasını garantiler.
Sonuç olarak Web Workers mekanizması; JavaScript'i tarayıcının dar kalıplarından çıkarıp, modern işlemcilerin çok çekirdekli gücünü kullanabilen
endüstriyel seviyede bir platforma dönüştürür.
İzolasyon sayesinde sağlanan güvenlik ve arka plan işleme gücü, yüksek performanslı web mimarisinin temel taşıdır.
Worker ve Ana İş Parçacığı İletişimi İletişim Mekanizması
Web Workers mimarisinde, ana iş parçacığı ve arka plan işçisi aynı bellek alanını doğrudan paylaşmazlar.
Bu izolasyon, veri çakışmalarını önlemek için tasarlanmıştır.
İletişim, Mesajlaşma adı verilen bir yöntemle kurulur.
Bir taraf diğerine veri göndermek istediğinde, bu veriyi bir "mesaj" olarak paketler ve karşı tarafa fırlatır.
Veri Gönderme: postMessage ve onmessageİş Akışı: Ana iş parçacığından Worker'a veri göndermek veya Worker'dan hesaplanmış bir sonucu geri almak için postMessage() metodu kullanılır.
Karşı taraf ise bu mesajı yakalamak için onmessage olay işleyicisini (event listener) aktif tutar.
Bu yapı, asenkron bir köprü kurarak ana iş parçacığının mesajın yanıtını beklerken bloklanmasını engeller.
Yapılandırılmış Klonlama (Structured Cloning)Kopyalama Maliyeti: Varsayılan olarak postMessage ile gönderilen nesneler, Yapılandırılmış Klonlama algoritmasıyla kopyalanır.
Yani veri, bir taraftan diğerine geçerken aslında tam bir kopyası oluşturulur.
Bu yöntem veri güvenliğini (bir tarafın veriyi bozmasının diğerini etkilememesini) sağlasa da, megabaytlarca büyüklükteki veri setlerinde kopyalama işlemi ciddi bir zaman ve bellek maliyeti yaratabilir.
Transfer Edilebilir Nesneler (Transferable Objects)Sahiplik Devri: Çok büyük veri setlerini ( Yüksek çözünürlüklü görüntü verileriveya ham binary dizileri ) kopyalamak yerine, Transfer Edilebilir Nesneler (özellikle ArrayBuffer) kullanılır.
Bu yöntemde veri kopyalanmaz; verinin bellekteki sahipliği bir iş parçacığından diğerine anında devredilir.
Performans Kilidi: Transfer işlemi gerçekleştikten sonra, veriyi gönderen taraftaki orijinal nesne "nötralize" olur.
Bu, verinin sıfır gecikme ile taşınmasını sağlayarak, yoğun veri işleme gerektiren uygulamalarda devasa performans kazancı sağlar.
Sonuç: Güvenli ve Hızlı Veri KöprüsüTüm bunların sonucu olarak Worker iletişimi; izolasyonun getirdiği güvenlik ile transfer edilebilir nesnelerin sunduğu hız arasında bir denge kurar.
Büyük ölçekli verilerle çalışırken kopyalama maliyetini yönetmek, Web Worker mimarisinin en kritik optimizasyon adımıdır.
Zayıf Referanslar (WeakMaps/WeakSets) Çözüm 2
Zayıf Referanslar, JavaScript'in bellek sızıntılarını daha oluşmadan önlemek için sunduğu en ileri ve zarif mimari çözümdür.
Geleneksel veri yapılarının (Map/Set) aksine, WeakMap ve WeakSet bir nesneye "zayıf" bir bağ ile tutunur.
Bu, şu anlama gelir: Eğer bir nesneye olan tüm diğer referanslar kopmuşsa, Çöp Toplayıcı bu nesneyi WeakMap içinde kayıtlı olsa bile bellekten silebilir.
Güçlü Referans Tuzağı vs. Zayıf ÇözümGüçlü Referans (Strong Reference): Standart bir Map içine bir nesneyi anahtar olarak koyduğunuzda, bu nesneye olan ihtiyacınız bitse bile, o nesne Map içinde olduğu sürece GC tarafından "hala canlı" kabul edilir.
Bu, özellikle DOM elementleri veya büyük veri objeleri söz konusu olduğunda devasa bellek sızıntılarına yol açar.
Zayıf Çözüm: WeakMap ve WeakSet, nesnenin yaşam süresini gereksiz yere uzatmaz.
Nesnenin asıl sahibi (ana kod akışı) o nesneyle vedalaştığında, WeakMap bu ayrılığa engel olmaz. Bu yapı, belleği rehin almadan veri depolamanın en güvenli yoludur.
Mimari Kullanım: DOM ve Private VeriZayıf referanslar, özellikle şu iki durumda vazgeçilmezdir:
1. DOM Elementi Verileri: Bir web bileşeni ekrandan kaldırıldığında, ona bağlı olan tüm meta verilerin de yok olması gerekir.
WeakMap kullanarak bir DOM elementine veri bağladığınızda, element silindiği an ona bağlı tüm ek bilgiler de otomatik olarak çöpe gider.
2. Gizli (Private) Sınıf Verileri: Sınıf örneklerine dışarıdan erişilemeyen veriler atamak için mükemmeldir.
Nesne yok edildiğinde, WeakMap'teki gizli bilgiler de iz bırakmadan silinir.
Sonuç olarak WeakMap ve WeakSet; geliştiricinin her şeyi manuel olarak temizleme yükünü azaltır.
Bellek yönetimini kodun akışına değil, verinin gerçek ihtiyacına bağlayan bu felsefe, modern ve ölçeklenebilir JavaScript mimarilerinin temel taşıdır.
Konsept Güçlü ve Zayıf Referanslar Arasındaki Ayrım
JavaScript'te varsayılan olarak kullandığımız tüm yapılar Güçlü Referans ilkesine dayanır.
Güçlü bir referans, bir nesnenin bellek yaşam döngüsüne ağır bir çapa atmak gibidir.
Bu çapa orada olduğu sürece, Çöp Toplayıcı (GC) nesneyi her taramada "erişilebilir" olarak işaretler.
Nesneye olan fiili ihtiyaç bitmiş olsa dahi, güçlü referans kaldırılmadığı sürece bellek serbest bırakılamaz.
Zayıf Referans: Saydam (Transparent) BağlantıWeakMap ve WeakSet tarafından kullanılan referanslar ise "zayıf" karakterdedir.
Bu referanslar GC için adeta saydamdır; yani GC, bir nesnenin çöpe atılıp atılmayacağına karar verirken bu zayıf bağları tamamen yok sayar.
Zayıf bir referans, nesneyi sadece izler ancak onun yaşam süresini bir milisaniye dahi uzatamaz.
Otomatik İmha: Bir nesneye bağlı olan son güçlü referans ( bir değişken veya dizi elemanı gibi ) ortadan kalktığında, GC nesneyi bellekten siler.
Bu gerçekleştiği anda, WeakMap veya WeakSet içindeki ilgili girdi de otomatik olarak buharlaşır.
Geliştiricinin bu kaydı manuel olarak silmesine gerek kalmaz.
Mekanik Fark: Neden İtera Edilemez?Zayıf referansların bu otonom doğası, teknik bir kısıtlamayı da beraberinde getirir: WeakMap ve WeakSet iterasyon edilemez.
Çünkü içerideki bir nesnenin ne zaman silineceği tamamen GC'nin keyfine bağlıdır.
Eğer liste üzerinde dönmek mümkün olsaydı, liste her an değişebileceği için programın davranışı öngörülemez hale gelirdi.
Sonuç olarak Güçlü Referanslar "sahiplik" bildirirken, Zayıf Referanslar sadece "ilişkilendirme" yapar.
Belleği rehin almadan veri tutabilme yeteneği, karmaşık sistemlerde bellek sızıntılarını mimari düzeyde engelleyen en zarif yöntemdir.
WeakMap Güçlü Referanssız Meta Veri Ekleme
WeakMap, bir nesnenin kendisini değiştirmeden veya ona yeni bir özellik eklemeden, o nesneye harici veriler atamak için tasarlanmış özel bir veri yapısıdır.
En büyük gücü, bu verileri iliştirirken nesneyi belleğe hapsetmemesidir.
Geliştirici, nesnenin yaşam döngüsünü kontrol etme stresine girmeden, nesne var olduğu sürece geçerli olan özel bilgiler saklayabilir.
Anahtar Kısıtlaması: Neden Sadece Nesneler?Heap Odaklı Yönetim: WeakMap'te anahtarlar mutlaka birer nesne olmalıdır.
Metin veya sayı gibi ilkel değerler anahtar olarak kullanılamaz.
Bunun nedeni, Çöp Toplayıcı (GC) mekanizmasının sadece Heap üzerinde yaşayan referans tiplerini "takip edilebilir veya edilemez" olarak işaretleyebilmesidir.
İlkel değerler kopyalanabilir ve sabit değerler oldukları için üzerlerinde "zayıf referans" mantığı yürütülemez.
Kritik Kullanım: DOM ve Otomatik TemizlikManuel Temizlikten Kurtuluş: WeakMap'in en yaygın kullanım alanı DOM elementlerine veri bağlamaktır.
Örneğin: Bir butona tıklandığında çalışacak özel bir önbellek verisini WeakMap içinde sakladığınızda; o buton sayfadan silindiği an, butona ait tüm bu özel veriler de otomatik olarak bellekten silinir. Geliştiricinin "bu buton silindi, şimdi gidip Map'ten verisini temizlemeliyim" demesine gerek kalmaz.
Teknik Kısıtlama: Öngörülemez BoyutWeakMap'in bellek sızıntısını önleme felsefesi, onu tekrarlanamaz bir yapı haline getirir.
.size, .keys() veya for...of gibi özellikler WeakMap'te bulunmaz.
Çünkü içerideki anahtarlar GC tarafından herhangi bir anda, sizin kodunuzdan bağımsız olarak silinebilir.
Boyutu her an değişebilen ve belirsiz olan bir yapı üzerinde toplu işlem yapmak, programın kararlılığını bozacağı için bu kısıtlama zorunludur.
Sonuç olarak WeakMap; nesnelerin yaşam süresine saygı duyarak veri saklamanın en güvenli yoludur.
Belleği kirletmeden, sızıntı riski taşımadan ve karmaşık temizlik rutinleri yazmadan akıllı meta veri yönetimi yapmanıza olanak tanır.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>DOM Elementi Verileri ve Otomatik Temizlik</title>
<link rel="stylesheet" href="weak-ref-logic.css?v=1.0.150">
</head>
<body>
<div class="weak-lab">
<div class="lab-header">
<h3>WeakMap: Akıllı Meta Veri Yönetimi</h3>
<p>DOM elementini sildiğinizde, ona bağlı verilerin bellekte kalıp kalmadığını gözlemleyin.</p>
</div>
<div class="simulation-area">
<div id="target-element" class="dom-node">Büyük DOM Nesnesi</div>
</div>
<div class="stats">
<div class="stat-box">Map (Strong): <span id="map-status">Veri Kilitli</span></div>
<div class="stat-box">WeakMap (Weak): <span id="weak-status">Esnek Bağ</span></div>
</div>
<div class="controls">
<button onclick="deleteElement()" id="del-btn" class="btn-action">DOM Elementini Sil (GC’ye Uygun Hale Getir)</button>
<button onclick="location.reload()" class="btn-reset" style="display:none;">Sıfırla</button>
</div>
<div class="info-note">
<strong>Mimari Not:</strong> WeakMap içindeki veri, element silindiğinde GC tarafından <em>potansiyel
olarak</em> silinmiş sayılır.
</div>
</div>
<script src="weak-ref-logic.js?v=1.0.150"></script>
</body>
</html>
.weak-lab {
border: 2px solid #3498db;
padding: 20px;
border-radius: 12px;
background: #f9fbff;
}
.dom-node {
padding: 20px;
background: #3498db;
color: white;
text-align: center;
border-radius: 8px;
margin: 20px 0;
transition: 0.5s;
}
.stats {
display: flex;
gap: 20px;
margin-bottom: 20px;
}
.stat-box {
flex: 1;
padding: 10px;
background: white;
border: 1px solid #ddd;
border-radius: 5px;
text-align: center;
font-size: 13px;
}
.btn-action {
background: #e74c3c;
color: white;
padding: 10px 20px;
border: none;
border-radius: 5px;
cursor: pointer;
width: 100%;
}
.btn-reset {
width: 100%;
padding: 12px 14px;
border-radius: 12px;
border: none;
background: linear-gradient(135deg, #f43f5e, #fb7185);
color: #ffffff;
font-weight: 700;
letter-spacing: 0.3px;
cursor: pointer;
transition: transform 0.15s ease, box-shadow 0.15s ease;
}
/* Hover */
.btn-reset:hover {
transform: translateY(-1px);
}
/* Active */
.btn-reset:active {
transform: scale(0.96);
box-shadow: 0 6px 15px rgba(244, 63, 94, 0.3);
}
/* Disabled */
.btn-reset:disabled {
opacity: 0.5;
cursor: not-allowed;
box-shadow: none;
}
.info-note {
font-size: 12px;
color: #666;
margin-top: 15px;
padding: 10px;
background: #eee;
border-radius: 4px;
}
.is-deleted {
opacity: 0;
transform: scale(0.5);
}
let element = document.getElementById("target-element");
const strongMap = new Map();
const weakMap = new WeakMap();
// Veri atama
strongMap.set(element, { data: "10MB Metadata" });
weakMap.set(element, { data: "10MB Metadata" });
function deleteElement() {
element.remove(); // DOM'dan sil
// Referansı null yaparak GC'nin önünü açıyoruz (Metinde anlattığınız gibi)
element = null;
document.getElementById("map-status").innerText =
"Sızıntı! (Referans Map'te kaldı)";
document.getElementById("weak-status").innerText =
"Güvende! (GC silebilir)";
document.getElementById("del-btn").style.display = "none";
document.querySelector(".btn-reset").style.display = "block";
}
WeakSet Üyelik Takibi ve Sınırlamalar
WeakSet, WeakMap ile aynı "zayıf referans" felsefesini paylaşan, ancak sadece nesne koleksiyonlarını ( benzersiz öğeler kümesini ) yönetmek için tasarlanmış bir yapıdır.
Bir nesnenin bir gruba dahil olup olmadığını takip etmenizi sağlar; ancak bu takip, nesnenin yaşam süresine müdahale etmez.
Nesne sistemden silindiğinde, WeakSet'teki varlığı da sessizce sona erer.
İçerik Kısıtlaması: Neden Sadece Nesneler?Sadece Referans Tipleri: WeakSet içine yalnızca nesneler ( Object, Array, Function ) eklenebilir.
Sayılar ( number ), metinler ( string ) veya boolean gibi ilkel ( primitive ) değerler eklenemez.
Bunun nedeni, ilkel değerlerin kopyalanabilir olması ve "zayıf referans" mantığının (bellek adresine dayalı takip) bu değerlerde uygulanamamasıdır.
Kullanım Senaryosu: "Bu nesne daha önce işlendi mi?" veya "Bu element şu an aktif mi?" gibi soruların cevabı için idealdir.
Örneğin: bir uygulamadaki seçili DOM elementlerini bir WeakSet içinde tutarsanız, element sayfadan kaldırıldığında koleksiyonu manuel olarak güncellemenize gerek kalmaz; bellek otomatik olarak temizlenir.
Teknik Kısıtlama: Neden İtera Edilemez?WeakSet ve WeakMap'in en dikkat çekici özelliği, .size özelliğinin olmaması ve içindeki elemanlar üzerinde döngü ( for...of ) kurulamamasıdır.
Bu durum bir eksiklik değil, bellek güvenliği için getirilmiş bilinçli bir kısıtlamadır.
GC Öngörülemezliği: Çöp Toplayıcı (GC) ne zaman çalışacağını bize söylemez.
Eğer bir WeakSet üzerinde döngü kurmaya izin verilseydi, bir iterasyon sırasında eleman sayısı 5 iken, bir sonraki milisaniyede GC'nin araya girmesiyle bu sayı 3'e düşebilirdi.
Tutarsızlık Riski: Bu belirsizlik, programın bir an çalışıp bir an hata vermesine ( non-deterministic behavior ) yol açardı.
Bu yüzden JavaScript, "içini göremediğiniz ama varlığını sorgulayabildiğiniz" bir yapı sunarak verimliliği korur.
Sonuç olarak WeakSet; geliştiriciyi "temizlik listesi tutma" yükünden kurtaran akıllı bir filtredir.
Nesnelerin üyelik durumlarını, belleği kirletmeden ve karmaşık "silme" mantıkları kurmadan yönetmek isteyen profesyonel mimariler için vazgeçilmez bir araçtır.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Asenkron Sızıntı Simülatörü Örneği</title>
<link rel="stylesheet" href="leak-detector.css?v=1.0.150">
</head>
<body>
<div class="leak-detector-card">
<h4>Asenkron Sızıntı Simülatörü</h4>
<p>Bir bileşeni sildiğinizde arkada çalışan 'setInterval' veya 'EventListener' temizlenmezse ne olur?</p>
<div class="simulation-box">
<div id="ghost-element" class="active-node">Aktif Bileşen</div>
</div>
<div class="leak-monitor">
Aktif Arka Plan İşlemleri: <span id="active-tasks">0</span>
</div>
<div class="controls">
<button onclick="startLeak()" class="btn-start">İşlemi Başlat ve Bileşeni Sil</button>
<button onclick="stopLeak()" class="btn-fix">Güvenli Temizlik (ClearInterval)</button>
</div>
</div>
<script src="leak-detector.js?v=1.0.150"></script>
</body>
</html>
/* byteomi.com - Asenkron Sızıntı Simülatörü Tasarımı */
:root {
--bg-dark: #121212;
--card-bg: #1e1e1e;
--danger: #ff4757;
--success: #2ed573;
--accent: #3742fa;
--text-main: #f1f2f6;
--text-dim: #a4b0be;
}
.leak-detector-card {
background-color: var(--card-bg);
border: 1px solid #333;
border-radius: 16px;
padding: 24px;
max-width: 500px;
margin: 20px auto;
font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
color: var(--text-main);
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);
}
.leak-detector-card h4 {
margin: 0 0 10px 0;
font-size: 1.4rem;
color: var(--danger);
letter-spacing: -0.5px;
}
.leak-detector-card p {
font-size: 0.95rem;
color: var(--text-dim);
line-height: 1.5;
margin-bottom: 20px;
}
.simulation-box {
background-color: rgba(0, 0, 0, 0.2);
border: 2px dashed #444;
border-radius: 12px;
height: 120px;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 20px;
position: relative;
overflow: hidden;
}
.active-node {
padding: 12px 24px;
background: linear-gradient(135deg, var(--accent), #5352ed);
color: white;
border-radius: 8px;
font-weight: 600;
box-shadow: 0 4px 15px rgba(55, 66, 250, 0.3);
transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
z-index: 2;
}
/* Sızıntı Başladığında Uygulanacak "Hayalet" Sınıfı */
.ghost-mode {
filter: grayscale(1) blur(1px);
opacity: 0.2;
transform: scale(0.8) translateY(-10px);
}
.leak-monitor {
background: rgba(255, 71, 87, 0.1);
border: 1px solid rgba(255, 71, 87, 0.2);
padding: 12px;
border-radius: 8px;
text-align: center;
font-size: 1rem;
margin-bottom: 20px;
color: var(--text-main);
}
#active-tasks {
font-family: 'Courier New', Courier, monospace;
font-weight: bold;
color: var(--danger);
font-size: 1.2rem;
display: inline-block;
min-width: 30px;
}
.controls {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 12px;
}
button {
padding: 12px;
border: none;
border-radius: 8px;
font-size: 0.85rem;
font-weight: 700;
cursor: pointer;
transition: all 0.3s ease;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.btn-start {
background-color: var(--danger);
color: white;
}
.btn-start:hover {
background-color: #ff6b81;
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(255, 71, 87, 0.4);
}
.btn-fix {
background-color: var(--success);
color: white;
}
.btn-fix:hover {
background-color: #7bed9f;
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(46, 213, 115, 0.4);
}
/* Sızıntı Alarm Animasyonu */
@keyframes pulse-danger {
0% {
background-color: rgba(255, 71, 87, 0.1);
}
50% {
background-color: rgba(255, 71, 87, 0.3);
}
100% {
background-color: rgba(255, 71, 87, 0.1);
}
}
.leaking-active {
animation: pulse-danger 1s infinite;
}
let intervalId = null;
let taskCount = 0;
function startLeak() {
const el = document.getElementById('ghost-element');
// Sızıntı başlıyor: setInterval temizlenmeden element silinecek
intervalId = setInterval(() => {
taskCount++;
document.getElementById('active-tasks').innerText = taskCount + " (Bellek Tüketiliyor...)";
console.log("Sızıntı çalışıyor: Bileşen yok ama kod hayatta!");
}, 1000);
el.classList.add('ghost-mode');
el.innerText = "DOM'dan Silindi (Ama Bellekte Rehin!)";
// DOM'dan kaldırıyoruz ama interval hala 'el' değişkenine (closure) referans tutuyor!
setTimeout(() => { if(el.parentNode) el.remove(); }, 500);
}
function stopLeak() {
clearInterval(intervalId);
taskCount = 0;
document.getElementById('active-tasks').innerText = "0 (Sistem Temiz)";
alert("Mimari Çözüm: clearInterval ile referans zinciri kırıldı.");
}
Chrome DevTools ile Çalışma Zamanı Profilleme Performans Optimizasyon Ana Konu Devamı
Çalışma Zamanı Profilleme, bir web uygulamasının kullanıcıyla etkileşime girdiği andaki gerçek performansını ölçen, teşhis eden ve görselleştiren ileri düzey bir analiz sürecidir.
En gelişmiş algoritmalar veya en temiz bellek yönetimi bile, tarayıcının Render İşlem Hattı'nı hatalı tetiklediğinde uygulamanın donmasına engel olamaz.
Profilleme araçları, kodun teorik doğruluğundan ziyade, CPU üzerindeki fiili baskısını ve ana iş parçacığındaki kullanım süresini somutlaştırır.
60 FPS Hedefi ve Render İşlem HattıAkıcı bir web deneyimi için altın kural saniyede 60 karedir.
Bu, tarayıcının her kareyi yaklaşık 16ms ( 1000ms / 60 ) içinde ekrana çizmesi gerektiği anlamına gelir.
Profilleme süreci, JavaScript'in bu 16ms'lik bütçenin ne kadarını tükettiğini ve geri kalan sürede Reflow ( Düzen ), Repaint ( Boyama ), ve Compositing ( Katman Birleştirme) işlemlerine ne kadar yer bıraktığını gösteren bir "röntgen" işlevi görür.
Tanı Kiti: Uzun Süren Görevler (Long Tasks)Takılmaların (Jank) Kaynağı: Ana iş parçacığını 50ms'den fazla meşgul eden her işlem bir "Long Task" olarak işaretlenir.
Profilleme araçları, bu görevleri zaman çizelgesi üzerinde kırmızı bayraklarla belirginleştirir.
Bu tespit, kullanıcı arayüzünde hissedilen anlık donmaların, hangi fonksiyonun hangi satırından kaynaklandığını kesin olarak ortaya çıkarır.
Bütüncül Analiz: CPU ve Bellek DengesiProfilleme sadece hıza odaklanmaz; aynı zamanda CPU ve Bellek arasındaki dengeyi de inceler.
Çöp Toplama döngülerinin ne zaman tetiklendiğini, bu tetiklenmelerin render işlemini ne kadar geciktirdiğini ve bellek tüketiminin zaman içindeki artış grafiğini eş zamanlı olarak sunar.
Bu, geliştiricinin sadece "çalışan" değil, "verimli çalışan" sistemler inşa etmesi için en temel tanı kitidir.
Sonuç olarak Çalışma Zamanı Profillemesi; performansı öznel bir his olmaktan çıkarıp, somut ve sayısal bir veri setine dönüştürür.
60 FPS hedefini korumak, Render İşlem Hattı'nı optimize etmek ve işlemciyi gereksiz yüklerden arındırmak, modern web mühendisliğinde
veriye dayalı kararlar almayı zorunlu kılar.
Performance Paneli CPU ve Render İşlem Hattı Analizi
Performance Paneli, bir web uygulamasının çalışma zamanı sırasındaki tüm biyometrik verilerini toplayan birincil analiz merkezidir.
Geliştiricinin sadece kodun çıktısına değil, o kodun CPU üzerindeki gerçek maliyetine ve tarayıcı kaynaklarını nasıl tükettiğine odaklanmasını sağlar.
Bu panel, soyut kod satırlarını somut birer zaman ve maliyet grafiğine dönüştürür.
Zaman Çizelgesi ve Kronolojik HaritalamaMain Thread Kaydı: Panel, kayıt (recording) süresince Ana İş Parçacığı üzerinde gerçekleşen her eylemin kronolojik bir haritasını çıkarır.
Her fonksiyon çağrısı, her olay dinleyicisi tetiklenmesi ve her asenkron işlem, bu zaman çizelgesi üzerinde birer blok olarak yer alır.
Bu sayede, "Hangi fonksiyon neden bu kadar uzun sürdü?" sorusunun cevabı saniyeler içinde görselleştirilir.
CPU Zaman Dağılımı: İşlem Hattı MetrikleriPerformance paneli, CPU'nun zamanını dört ana kategoride nasıl harcadığını detaylandırır:
Scripting (Sarı): JavaScript kodunun yürütülme süresi.
Rendering/Layout (Mor): Sayfa düzeninin (Reflow) hesaplanma süresi.
Painting (Yeşil): Elementlerin piksellere dönüştürülüp boyanma süresi.
Idle (Gri): İşlemcinin boşta kaldığı ve yeni görevler için hazır olduğu süre.
Kritik Görev: Uzun Süren Görevlerin (Long Tasks) Tespiti60 FPS Bariyeri: Panelin en hayati fonksiyonu, 60 FPS hedefini tehdit eden unsurları ayıklamaktır.
50ms'den uzun süren her görev zaman çizelgesinin sağ üst köşesinde kırmızı bir çentik ile işaretlenir.
Bu "Long Task" uyarıları, kullanıcının hissettiği takılmaların ( jank ) tam olarak nerede ve neden oluştuğunu kanıtlar, bu noktaları tespit etmek, optimizasyon sürecinin %80'ini oluşturur.
Sonuç olarak Performance paneli, geliştiriciye tahmine dayalı değil, veriye dayalı bir optimizasyon imkanı sunar.
CPU'nun zamanını nerelere harcadığını görmek, sadece kodun hızını artırmakla kalmaz, aynı zamanda donanım kaynaklarını en verimli şekilde kullanan üst düzey bir mimari disiplin kazandırır.
Kayıt Süreci ve Zaman Çizelgesi Performans Paneline Erişim
Kayıt Süreci, Performans panelindeki "Record" butonuna bastığınız andan itibaren tarayıcının tüm savunma mekanizmalarını ve günlük tutma sistemlerini devreye almasıdır.
Bu süre zarfında tarayıcı, Ana İş Parçacığı üzerinde gerçekleşen her türlü fısıltıyı kaydeder: Karmaşık fonksiyon çağrıları, anlık DOM güncellemeleri, ağ üzerinden gelen veri paketleri ve hatta arka planda çalışan Çöp Toplama döngüleri.
Bu süreç, uygulamanızın o anki yaşam döngüsünün dijital bir "röntgeni" gibidir.
Zaman Çizelgesi: FPS ve CPU Arasındaki KorelasyonKayıt durdurulduğunda sunulan harita, iki kritik veriyi üst üste bindirir: Üstte uygulamanın akıcılığını simgeleyen FPS grafiği, altta ise işlemcinin o kareleri üretmek için ne kadar ter döktüğünü gösteren CPU grafiği.
Eğer FPS grafiğinde ani düşüşler görüyorsanız, bu durum tam o milisaniyede CPU'nun aşırı yüklendiğinin ve bir karenin 16ms'lik sürede yetişmediğinin kesin kanıtıdır.
Darboğaz Teşhisi: Long Tasks ve Renk Kodları50ms Sınırı: Analizin ana hedefi, kullanıcı arayüzünü felç eden Uzun Süren Görevleri ayıklamaktır.
Ana iş parçacığını 50 milisaniyeden fazla bloke eden her görev, zaman çizelgesinde "tehlike" olarak işaretlenir.
Geliştirici bu haritaya baktığında sorunun kaynağını renkler aracılığıyla anında anlar:
Sarı Bloklar: Sorun JavaScript kodunuzdaki ağır bir algoritma veya sonsuz döngüdedir.
Mor Bloklar: Sorun tarayıcının sayfayı yeniden hesaplamaya zorlanmasındadır.
Sonuç olarak Performans paneli, soyut bir yavaşlık hissini somut bir zaman-mekan haritasına dönüştürür.
Yatay eksende zamanı izleyerek yavaşlamanın nerede başladığını, dikey eksende ise işlemci derinliğini inceleyerek hangi fonksiyonun buna neden olduğunu bulmak; bir geliştiriciyi "tahmin yürüten" birinden, "cerrahi hassasiyetle sorun çözen" bir mühendise dönüştürür.
CPU Grafiği ve Renk Kodlaması Genel Bilgi
CPU Grafiği, performans kaydı boyunca işlemcinin saniyeler içindeki meşguliyetini temsil eder.
Bu grafik, sadece "işlemci dolu mu?" sorusuna değil, "işlemci neyle dolu?" sorusuna yanıt verir.
Normal şartlarda tarayıcı motorunun içinde gerçekleşen ve geliştiriciden gizlenen karmaşık operasyonlar, bu grafikte renkli katmanlar halinde sunulur.
Grafiğin yüksekliği işlemci yükünü, genişliği ise süreyi ifade eder.
Renklerin Dili: Teknik Kategorizasyon ,CPU grafiğindeki her renk, tarayıcı işlem hattındaki farklı bir aşamayı temsil eder:
Sarı (Scripting): JavaScript motorunun kodlarınızı yürüttüğü süredir.
Eğer sarı alan grafiği domine ediyorsa, algoritmalarınızın veya asenkron görevlerinizin işlemciyi çok yorduğu söylenebilir.
Mor (Rendering): Tarayıcının DOM ağacını stil kurallarıyla birleştirip elemanların konumlarını hesapladığı (Layout/Reflow) süredir. Mor yoğunluğu, CSS değişikliklerinin veya DOM manipülasyonlarının maliyetli olduğunu gösterir.
Yeşil (Painting): Hesaplanan yerleşimlerin piksellere dönüştürülüp ekrana çizildiği süredir.
Görsellerin işlenmesi ve efektlerin boyanması bu kategoridedir.
Gri (System / Idle): İşlemcinin kendi dahili işleri veya boşta beklediği zamanlardır.
Tanısal Değer: Performans Hırsızlarını YakalamakBlokaj Analizi: Bu renk kodlamasının temel amacı, kullanıcı arayüzünü felç eden "Long Task" içindeki suçluyu belirlemektir.
Bir takılma anında grafik üzerinde mor bir patlama görüyorsanız, çözüm JavaScript optimizasyonunda değil, CSS ve Layout stratejilerindedir.
Sarı bir blok görüyorsanız, o noktadaki fonksiyon çağrılarını ( Flame Chart üzerinden ) inceleyerek kodunuzun hangi parçasının işlemciyi kilitlediğini anlayabilirsiniz.
Sonuç olarak CPU grafiği, bir web uygulamasının performansını optimize ederken başvurulacak en net teşhis haritasıdır.
Renklerin dengesi, uygulamanızın hangi alanda ( kod, stil veya çizim ) darboğaz yaşadığını saniyeler içinde göstererek, optimizasyon eforunuzu en doğru noktaya kanalize etmenizi sağlar.
Sarı (Scripting - JavaScript Yürütme) CPU Grafiği Renk Kodlaması
Sarı Renk, CPU'nun JavaScript motoru aracılığıyla kodlarınızı işlediği süreyi ifade eder.
Bu süre sadece sizin yazdığınız kodları değil; olay işleyicilerinin ( event listeners ) tetiklenmesini, zamanlayıcıların ( setTimeout/setInterval ) çalışmasını, fetch/asenkron işlemlerin geri dönüşlerini ve framework'lerin ( React, Vue vb.) arka plandaki yönetim süreçlerini kapsar.
Kritik Çıkarım: Blokaj ve "Jank" EtkisiAna İş Parçacığı Rehineleri: Performans grafiğinde gördüğünüz uzun ve kesintisiz sarı çubuklar, birer "tehlike" sinyalidir.
JavaScript tek iş parçacıklı çalıştığı için, o sarı çubuk bitene kadar tarayıcı başka hiçbir şey yapamaz; ne bir butona basılmasına yanıt verebilir ne de ekrandaki bir animasyonu oynatabilir.
Bu durum, kullanıcı tarafından "donma" veya "takılma" olarak algılanır.
Yüksek Scripting Süresinin Temel NedenleriEğer CPU grafiğiniz sarı renkle domine edilmişse, genellikle şu üç sorundan biri yaşanıyordur:
1. Ağır Algoritmalar: Çok büyük diziler üzerinde yapılan iç içe döngüler veya karmaşık veri işleme süreçleri.
2. Senkron İşlemler: Büyük bir JSON dosyasının ana iş parçacığında ayrıştırılması veya bloke edici kütüphane çağrıları.
3. Aşırı Fonksiyon Çağrısı: Özellikle scroll veya resize gibi olaylarda, saniyede yüzlerce kez çalışan ve optimize edilmemiş (throttle/debounce uygulanmamış) fonksiyonlar.
Sonuç olarak sarı alanları analiz etmek, kodunuzun sadece "doğru" çalışıp çalışmadığını değil, "saygılı" çalışıp çalışmadığını gösterir. Sarı blokları parçalara bölmek ( Task Splitting ) veya CPU yoğun işleri Web Workers'a devretmek, uygulamanızı akıcı hale getirmenin en profesyonel yoludur.
Mor (Rendering/Layout - Geometri Hesaplama) CPU Grafiği Renk Kodlaması
Mor Renk, tarayıcının Layout veya yaygın adıyla Reflow sürecini temsil eder.
JavaScript bir elementin stilini değiştirdiğinde veya DOM'a yeni bir eleman eklediğinde, tarayıcı bu değişikliğin tüm sayfa geometrisini nasıl etkilediğini hesaplamak zorundadır.
Bir kutunun genişliği değiştiğinde, onun yanındaki ve altındaki tüm kutuların da yerinden oynaması mor alanın büyümesine neden olur.
Kritik Çıkarım: Verimsiz DOM ManipülasyonuGeometri Baskısı: Performans grafiğinde görülen yüksek ve sık mor çubuklar, tarayıcının sürekli bir "yerleşimi hesaplama" döngüsüne hapsolduğunu gösterir.
width, height, margin, left veya top gibi geometriyi doğrudan etkileyen CSS özelliklerini JavaScript ile dinamik olarak değiştirmek, tarayıcıyı her seferinde tüm sayfa ağacını taramaya zorlar.
Sinsi Tehlike: Layout Thrashing (Yerleşim Çarpınımı)Mor alanların en büyük suçlusu, Layout Thrashing adı verilen "oku-yaz" karmaşasıdır.
Eğer kodunuzda bir elementin konumunu okuyup ( offsetTop gibi ) hemen ardından başka bir elementin stilini değiştirirseniz ve bunu bir döngü içinde yaparsanız, tarayıcıyı her adımda güncel bilgiyi vermek için Reflow yapmaya zorlarsınız.
Bu durum, CPU grafiğinde mor bir "gürültü" ve devasa performans kayıpları yaratır.
Optimizasyon Stratejisi: Geometriden KaçınmakKompozisyonun Gücü: Mor süreleri azaltmanın yolu, geometriyi etkileyen özellikler yerine transform ve opacity gibi tarayıcının "Compositor" katmanında çözebileceği özellikleri kullanmaktır.
Görsel güncellemeleri toplu halde ( batching ) yapmak ve DOM okuma/yazma işlemlerini birbirinden ayırmak, mor blokların yerini çok daha ucuz olan yeşil veya gri alanlara bırakmasını sağlar.
Sonuç olarak mor alanlar, uygulamanızın CSS mimarisinin ve DOM yönetiminin verimlilik karnesidir.
Mor süresini minimize etmek, sadece CPU'yu rahatlatmakla kalmaz; pil ömründen kullanıcı tepkiselliğine kadar her noktada uygulamanızın kalitesini artırır.
Yeşil (Painting - Pikselleri Çizme) CPU Grafiği Renk Kodlaması
Yeşil Renk, tarayıcının Painting aşamasını temsil eder.
Bu süreçte tarayıcı, Mor aşamasında yerleri belirlenen kutuları alır ve içlerini gerçek piksellerle doldurur.
Metinlerin çizilmesi, arka plan renklerinin uygulanması, kenarlıkların ve gölgelerin oluşturulması bu aşamada gerçekleşir.
Mor alan bir "mimari plan" ise, Yeşil alan o planın "boyanması ve dekorasyonu"dur.
Kritik Çıkarım: Geometrisiz Görsel GüncellemeDaha Az Maliyetli Değişim: Yeşil çubuklar, Mor çubuklara (Reflow) kıyasla genellikle daha az maliyetlidir.
Bunun sebebi, color, visibility veya background-color gibi özellikler değiştiğinde tarayıcının nesnelerin konumunu yeniden hesaplamak zorunda kalmamasıdır.
Sadece etkilenen alanın pikselleri güncellenir, ancak bu, yeşil alanların tamamen göz ardı edilebileceği anlamına gelmez.
Performans Hırsızı: Karmaşık Görsel EfektlerAğır Boyama İşleri: Eğer CPU grafiğinizde çok sık ve geniş yeşil bloklar görüyorsanız, bu durum tarayıcıyı "yorucu" bir boyama işlemine zorladığınızın işaretidir.
Özellikle büyük alanları kapsayan box-shadow (gölge) efektleri, karmaşık border-radius (köşe yuvarlama) kombinasyonları ve yoğun filter (blur vb.) kullanımı, yeşil süresini artırarak CPU ve GPU üzerindeki baskıyı büyütür.
Optimizasyon Stratejisi: Katman YönetimiGereksiz Boyamadan Kaçınmak: Yeşil maliyetini düşürmenin en iyi yolu, sayfanın tamamını boyamak yerine sadece değişen parçaları boyamaktır.
Geliştiriciler, Performance panelindeki "Enable advanced paint instrumentation" seçeneğini kullanarak hangi görsel efektin daha fazla "ms" tükettiğini görebilirler.
Ayrıca, animasyonlu öğeleri kendi katmanlarına ayırarak, ana sayfayı sürekli yeniden boyama zahmetinden kurtarabilirler.
Sonuç olarak yeşil alanlar, uygulamanızın estetik yükünü ölçer.
Modern web uygulamalarında hedef, boyama maliyetlerini düşük tutarak işlemciyi asıl işi olan JavaScript yürütmesine veya boşta kalmaya teşvik etmektir.
Azalan yeşil süresi, daha serin çalışan cihazlar ve daha uzun pil ömrü demektir.
Gri/Beyaz (System/Idle - Boşta Kalma) CPU Grafiği Renk Kodlaması
Beyaz ve Gri Alanlar, işlemcinin doğrudan sizin JavaScript kodunuzu çalıştırmadığı veya bir görselleştirme yapmadığı zamanları ifade eder.
Beyaz ( Idle ) alanlar işlemcinin tamamen boşta olduğunu ve kullanıcının bir sonraki etkileşimi için hazır beklediğini gösterirken; Gri ( System ) alanlar tarayıcının ağ iletişimi, dosya okuma/yazma ve bellek temizliği gibi kendi "ev işleri" ile meşgul olduğunu simgeler.
Beyaz Alanın Gücü: Giriş TepkiselliğiOptimizasyonun Kanıtı: Yüksek oranda beyaz alan görmek, uygulamanızın kaynakları verimli kullandığının ve Giriş Tepkiselliğinin (Input Responsiveness) çok yüksek olduğunun en net göstergesidir.
İşlemci ne kadar çok boşta kalırsa, kullanıcının yaptığı bir tıklama veya kaydırma hareketine o kadar hızlı ( genellikle 100ms'nin çok altında ) yanıt verebilir ve bu, modern web performansının nihai hedefidir.
Gri Alan ve GC Sinyalleri: Gizli İş yüküBellek Yönetimi Alarmı: Eğer CPU grafiğinde gri alanlar aniden yükseliyorsa ve bu yükselişler düzenli aralıklarla tekrarlanıyorsa, bu durum genellikle Çöp Toplama ( Garbage Collection - GC ) döngülerine işarettir.
Tarayıcı, kodunuzun yarattığı "çöpleri" temizlemek için ana iş parçacığını kısa süreliğine "System" moduna sokar.
Kritik Uyarı: Çok yoğun gri alanlar, uygulamanızın gereğinden fazla nesne yarattığını ( Memory Pressure ) veya bir bellek sızıntısı ile boğuştuğunu gösterir.
Bu durumda, sadece CPU'yu değil, Memory panelini de incelemek zorunlu hale gelir.
Sonuç olarak, ideal bir performans grafiği; görevler arasında yeterli Beyaz boşluklar bırakan ve Gri yükünü minimumda tutan bir yapıdadır.
Bu denge, uygulamanızın sadece hızlı olmasını değil, aynı zamanda kararlı ve düşük güç tüketen bir kullanıcı dostu olmasını sağlar.
Bellek Sızıntılarını Tespit Etme () Memory Panel
Memory Paneli, uygulamanın işlemci hızından ziyade "hacmine" odaklanan bir mühendislik terminalidir.
Performance panelinin aksine, burada zamanın nasıl harcandığını değil, belleğin (özellikle Heap) nasıl işgal edildiğini görürüz.
Çöp Toplayıcı'nın neden bazı nesneleri silemediğini anlamak için gereken tüm kanıtlar; nesneler arası bağlantılar ve referans yolları bu panelde saklıdır.
Heap Snapshot: Belleğin Fotoğrafik AnısıAnlık Durum Analizi: Bellek sızıntılarını yakalamanın en etkili yolu Heap Snapshot ( Bellek Anlık Görünümü ) almaktır.
Bu işlem, o milisaniyede uygulamanın belleğinde yaşayan tüm nesnelerin, dizilerin ve fonksiyonların "fotoğrafını" çeker.
İki farklı zaman diliminde alınan Snapshot'ları karşılaştırarak, hangi nesnelerin silinmesi gerekirken hala bellekte kalmaya devam ettiğini sayısal olarak görebiliriz.
Retainers: Nesneyi Hayatta Tutan BağlarReferans Zinciri: Memory panelinin en hayati bölümü Retainers ( Tutucular ) kısmıdır.
Bir nesnenin neden bellekte kaldığını merak ediyorsanız, panel size o nesneye "kimin" referans verdiğini bir ağaç yapısı şeklinde gösterir.
Eğer bir DOM elementi sayfadan silinmiş olmasına rağmen bellekteyse, Retainers sekmesi o elementi hala bir global değişkenin mi yoksa unutulmuş bir Closure'ın mı "rehin" tuttuğunu kesin olarak ifşa eder.
Performans ve Kararlılık İlişkisiSinsi Sızıntıların Sonu: Bellek sızıntıları genellikle aniden değil, sinsi bir birikimle uygulamayı yavaşlatır.
Memory paneli sayesinde, geliştiriciler "kasıtsız güçlü referansları" erkenden tespit ederek uygulamanın uzun vadeli kararlılığını garanti altına alırlar.
Bu araç, sadece hata ayıklamak için değil, uygulamanın bellek ayak izini ( memory footprint ) küçültmek için de vazgeçilmezdir.
Sonuç olarak Memory paneli; Çöp Toplayıcı'nın "erişilebilirlik" teorisini somut verilere döker.
Uygulamanızın belleği neden tükettiğini tahmin etmek yerine, referans zincirlerini takip ederek sorunu kaynağında çözmek, modern web geliştiriciliğinin en ileri aşamasıdır.
Temel Mekanizma Heap Snapshots (Yığın Anlık Görüntüleri)
Heap Snapshot, bir bellek sızıntısını "tahmin" etmek yerine "ispat" etmenizi sağlayan birincil araçtır.
Bu işlem, uygulamanın belleğinde o an yaşayan her bir nesnenin, dizinin ve fonksiyonun, birbirlerine nasıl bağlandıklarını gösteren referans zincirlerinin eksiksiz bir haritasını çıkarır.
Sızıntı tespiti, bu haritaların zaman içindeki değişimini izleyerek yapılır.
Üç Aşamalı Kanıtlama Yöntemi (Delta Analizi)Profesyonel bir bellek analizi, "karşılaştırmalı" (delta) bir metodoloji izler:
1. Baseline (Referans Noktası): Uygulama ilk açıldığında veya stabil durumdayken İlk Snapshot alınır.
Bu, sistemin sağlıklı bellek yükünü temsil eder.
2. Stres Testi: Sızıntı yaptığından şüphelenilen işlem ( bir sayfanın açılıp kapanması gibi ) 5-10 kez üst üste tekrarlanır. Amaç, küçük sızıntıları biriktirerek analizde görünür hale getirmektir.
3. Delta Karşılaştırma: İşlem bittikten sonra İkinci Snapshot alınır. DevTools'un "Comparison" modu sayesinde, iki an arasında belleğe eklenmiş ancak silinmemiş olan nesneler (delta) net bir şekilde ortaya çıkar.
Maliyet Analizi: Shallow Size vs. Retained SizeBellek sızıntısının gerçek yükünü anlamak için iki kritik metrik kullanılır:
Shallow Size: Nesnenin bellekte kapladığı ham, kişisel boyuttur.
Retained Size (Tutulan Boyut): Bir sızıntının asıl maliyetidir.
Bu değer, bir nesnenin kendisiyle birlikte bellekte rehin tuttuğu tüm bağımlı nesnelerin toplam boyutunu gösterir.
Eğer bir nesneyi sildiğinizde sistemden 5MB alan boşalacaksa, o nesnenin Retained Size değeri 5MB'dır.
Referans Zinciri (Retention Path) ve ÇözümKök Neden Tespiti: Sızıntı yapan nesne bulunduğunda, panelin alt kısmındaki Retention Path (Tutma Yolu) incelenir.
Bu yol, nesneyi Çöp Toplayıcı köklerine bağlayan "kasıtsız güçlü referansı" gösterir.
Örneğin: Silinmesi gereken bir dizi, hala bir global setInterval içindeki closure tarafından mı tutuluyor?
Bu sorunun cevabı, sızıntıyı kod seviyesinde çözmeniz için gereken tek kanıttır.
Özet olarak Heap Snapshot analizi; performansı tesadüfe bırakmayan, her megabaytın hesabını soran analitik bir yaklaşımdır.
Bu yöntemle temizlenen bir uygulama, haftalarca açık kalsa bile şişmeyen, çökmeyen ve kullanıcıyı yarı yolda bırakmayan yüksek kaliteli bir yazılım standardına ulaşır.
Analiz ve Referans Zinciri İzleme Genel Bilgi
Analiz Süreci, bir bellek sızıntısının varlığını kanıtladıktan sonra, o sızıntının "neden" kaynaklandığını bulduğumuz dedektiflik aşamasıdır.
Heap Snapshot sonuçları; nesneleri türlerine, miktarlarına ve boyutlarına göre listelerken, bize sadece bir liste sunmaz; aynı zamanda her bir nesnenin bellek hiyerarşisindeki yerini gösterir.
Bu aşamada hedef, bellekteki kalabalığın içinden "istenmeyen misafirleri" ve onları orada tutan "ev sahiplerini" ayıklamaktır.
Retained Size: Sızıntının Gerçek MaliyetiZincirleme Etki: Analizdeki en kritik metrik Retained Size (Tutulan Boyut) değeridir.
Bu değer, bir nesnenin sadece kendi kapladığı alanı değil, o nesne canlı kaldığı için bellekte tutulmak zorunda olan tüm alt nesnelerin toplam ağırlığını gösterir.
Büyük Resim: Örneğin, küçük bir Closure fonksiyonu kendi başına sadece birkaç bayt olabilir; ancak bu fonksiyon 10MB'lık bir veri dizisine referans veriyorsa, fonksiyonun Retained Size değeri 10MB'dır.
Bu metrik, hangi nesneyi sildiğimizde belleğin ne kadar rahatlayacağını gösteren en dürüst kılavuzdur.
Referans Ağacı (Retention Path): Suç Mahalini İzlemekTersine Haritalama: Bir nesneye tıklandığında açılan Retention Path, o nesneyi Çöp Toplayıcı köklerine bağlayan görünmez halatları görünür kılar.
Bu ağaç yapısı, nesneden geriye doğru giderek onu kimin "rehin" tuttuğunu adım adım gösterir.
Kırılma Noktası: Geliştirici bu yolu inceleyerek; "Bu DOM elementi neden hala bellekte?" sorusuna yanıt bulur.
Belki de yolun sonunda, üç sayfa önce yok edilmesi gereken bir event listener veya bir global diziye yanlışlıkla eklenmiş bir referans vardır.
Bu zincirdeki kasıtsız güçlü referans, sızıntının kaynağıdır.
Sonuç olarak Referans Zinciri izleme, sızıntıyı kod seviyesinde durdurmak için gereken kesin kanıtı sağlar.
Zincirdeki kırılma noktasını tespit edip o bağı kopardığınızda ( referansı null yaparak veya olay dinleyiciyi kaldırarak ), Çöp Toplayıcı tüm o devasa "rehin" veri grubunu tek bir hamlede serbest bırakır.
Bellek Tahsis Enstrümantasyonu Allocation Instrumentation
Bellek Tahsis Enstrümantasyonu, Heap Snapshot'ın sunduğu durağan "anlık fotoğraf" yaklaşımından farklı olarak, belleğin nasıl harcandığını canlı bir film gibi izlemenizi sağlar.
Bu yöntem, uygulamanın çalışması sırasında hangi milisaniyede ne kadar bellek talep edildiğini ( allocation ) grafiksel bir zaman çizelgesi üzerinde haritalandırır. Bu, belleğin sadece "miktarına" değil, "tüketim hızına" odaklanan bir analizdir.
Fonksiyonel Sorumluluk: Suçlu Fonksiyonu BulmakDoğrudan Teşhis: Bu aracın en güçlü yanı, zaman çizelgesindeki her bir bellek artışını, o artışa neden olan fonksiyon çağrısına bağlamasıdır.
Kayıt bittiğinde, grafikteki bir yükselişe tıkladığınızda DevTools size doğrudan o belleği isteyen JavaScript satırını gösterir.
Bu, geliştiricinin "Hangi kodum sistemi şişiriyor?" sorusuna saniyeler içinde yanıt almasını sağlar.
Odak Noktası: Performans ve AkıcılıkSızıntı Değil, Verimlilik: Tahsis enstrümantasyonu sadece sızıntıları bulmak için değil, asıl olarak yüksek performanslı kod yazımı için kullanılır.
Bir uygulama sızıntı yapmasa bile, her saniye binlerce geçici nesne oluşturup siliyorsa, Çöp Toplayıcı sürekli devreye girerek UI'da takılmalara neden olur ve bu araç, bu "gereksiz trafik" noktalarını tespit eder.
Optimizasyon Hedefi: Geçici Nesne FırtınasıHassas Alanlar: Özellikle 60 FPS hızında çalışan animasyon döngüleri ( requestAnimationFrame ) veya yoğun veri işleyen olay işleyicileri içinde her seferinde yeniden yaratılan new Array() veya new Object() çağrıları, bellek tahsis profilinde devasa dalgalanmalar yaratır.
Bu noktaları tespit edip nesneleri yeniden kullanmak ( Object Pooling ), işlemci üzerindeki yükü dramatik şekilde azaltır.
Sonuç olarak Bellek Tahsis Enstrümantasyonu; kodunuzun bellek sistemine ne kadar "nazik" davrandığını ölçer.
Gereksiz tahsisleri budamak, sadece bellek kullanımını düşürmekle kalmaz; aynı zamanda Çöp Toplayıcıyı sakinleştirerek uygulamanızın yağ gibi akmasını sağlar.
|
Metot
|
Odak Noktası
|
Mekanizma ve Detaylı Amaç
|
Kritik Ölçüt
|
|---|---|---|---|
|
Heap Snapshot
(Yığın Anlık Görüntüsü) |
Kalıcı Referans Zincirleri.
|
Uygulamanın bellek durumunun belirli bir andaki fotoğrafını çekerek, GC (Çöp Toplayıcı)
Kökleri'ne
istem dışı güçlü referanslarla bağlı kalmış, bellekteki gereksiz nesneleri (sızıntıları)
kanıtlar.
Bu,
uygulamanın uzun vadeli stabilite sorunlarını tespit etmek için esastır.
|
Retained Size (Tutulan Boyut): Bellekte tutulan nesne zincirinin toplam
maliyeti.
|
|
Allocation Instrumentation
(Tahsis Enstrümantasyonu) |
Anlık Tahsis Sıklığı ve Boyutu.
|
Uygulama çalışırken, bellek tahsislerinin (yeni nesne yaratımı) zaman çizelgesi üzerinde
kronolojik
kaydını tutar. Amaç, pahalı new Object() çağrılarının anlık sıklığını belirleyerek, sık
tahsis
nedeniyle
oluşan yüksek CPU/GC yükünü ve kısa vadeli akıcılık sorunlarını tespit etmektir.
|
Allocation Spikes (Tahsis Ani Yükselişleri): Hangi fonksiyonun, hangi
milisaniyede ve
ne kadar bellek tahsisi yaparak GC'yi gereksiz yere zorladığını gösterir.
|
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>DevTools Performance Örneği</title>
<link rel="stylesheet" href="performance-lab.css?v=1.0.150">
</head>
<body>
<div class="dashboard">
<div class="card scripting">
<h3>1. Sarı (Scripting)</h3>
<p>Ağır algoritmalar ana thread'i bloke eder. DevTools'da uzun sarı bloklar görünür.</p>
<div class="visual-box" id="scripting-status">Beklemede</div>
<button onclick="runScripting()">Sarı İşlemi Başlat</button>
</div>
<div class="card rendering">
<h3>2. Mor (Rendering)</h3>
<p>Layout Thrashing (oku-yaz) tarayıcıyı Reflow yapmaya zorlar. Mor dalgalanmalar oluşur.</p>
<div class="visual-box" id="render-box">Reflow Kutu</div>
<div id="rendering-status" style="font-size: 11px; text-align: center;"></div>
<button onclick="runRendering()">Mor İşlemi Başlat</button>
</div>
<div class="card painting">
<h3>3. Yeşil (Painting)</h3>
<p>Geometri değişmeden sadece görsel (renk/gölge) değişirse 'Paint' tetiklenir.</p>
<div class="visual-box" id="paint-box">Repaint Kutu</div>
<div id="painting-status" style="font-size: 11px; text-align: center;"></div>
<button onclick="runPainting()">Yeşil İşlemi Başlat</button>
</div>
<div class="card system">
<h3>4. Gri (System/GC)</h3>
<p>Büyük veri blokları silindiğinde GC devreye girer. Gri 'spike'lar oluşur.</p>
<div class="visual-box" id="system-status">GC Hazır</div>
<button onclick="runGC()">Gri İşlemi Başlat</button>
</div>
</div>
<script src="performance-lab.js?v=1.0.150"></script>
</body>
</html>
:root {
--scripting: #f1c40f;
/* Sarı */
--rendering: #9b59b6;
/* Mor */
--painting: #2ecc71;
/* Yeşil */
--system: #95a5a6;
/* Gri */
--bg: #f4f7f6;
--card: #ffffff;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: var(--bg);
padding: 40px;
}
.dashboard {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 20px;
max-width: 1200px;
margin: 0 auto;
}
.card {
background: var(--card);
padding: 20px;
border-radius: 12px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
border-top: 5px solid #ccc;
transition: transform 0.2s;
}
.card:hover {
transform: translateY(-5px);
}
/* Renk Kodlu Kartlar */
.card.scripting {
border-top-color: var(--scripting);
}
.card.rendering {
border-top-color: var(--rendering);
}
.card.painting {
border-top-color: var(--painting);
}
.card.system {
border-top-color: var(--system);
}
h3 {
margin-top: 0;
color: #333;
font-size: 1.1rem;
}
p {
font-size: 0.85rem;
color: #666;
line-height: 1.4;
}
.visual-box {
height: 60px;
background: #eee;
margin: 15px 0;
border-radius: 6px;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
color: #555;
transition: all 0.3s;
}
button {
width: 100%;
padding: 10px;
border: none;
border-radius: 6px;
cursor: pointer;
font-weight: 600;
transition: opacity 0.3s;
}
.card.scripting button {
background: var(--scripting);
color: #000;
}
.card.rendering button {
background: var(--rendering);
color: #fff;
}
.card.painting button {
background: var(--painting);
color: #fff;
}
.card.system button {
background: var(--system);
color: #fff;
}
button:active {
opacity: 0.7;
}/code>
// 1. SARI: AĞIR SCRIPTING (Long Task)
function runScripting() {
console.log("Scripting testi başladı...");
const start = performance.now();
let total = 0;
// 500 milyon döngü - Ana thread'i kilitler (Sarı çubuk)
for (let i = 0; i < 500000000; i++) {
total += Math.sqrt(i);
}
const end = performance.now();
document.getElementById("scripting-status").innerText =
`Tamamlandı: ${(end - start).toFixed(0)}ms`;
}
// 2. MOR: LAYOUT THRASHING (Reflow)
function runRendering() {
const box = document.getElementById("render-box");
let width = 100;
console.time("Rendering");
for (let i = 0; i < 500; i++) {
box.style.width = width + (i % 100) + "px"; // WRITE
const read = box.offsetWidth; // READ (Zorunlu Reflow)
}
console.timeEnd("Rendering");
document.getElementById("rendering-status").innerText =
"Reflow Tetiklendi (Mor)";
}
// 3. YEŞİL: REPAINT
function runPainting() {
const box = document.getElementById("paint-box");
let count = 0;
const interval = setInterval(() => {
// Geometriyi değiştirmeden sadece rengi değiştiriyoruz (Yeşil çubuk)
box.style.backgroundColor = count % 2 === 0 ? "#e74c3c" : "#f1c40f";
count++;
if (count > 40) clearInterval(interval);
}, 30);
document.getElementById("painting-status").innerText =
"Boyama Yapılıyor (Yeşil)";
}
// 4. GRİ: GC TETİKLEME
let gcMemoryStore = [];
function runGC() {
document.getElementById("system-status").innerText = "Bellek şişiriliyor...";
for (let i = 0; i < 40; i++) {
gcMemoryStore.push(new Array(1000000).fill("Byteomi Lab Data"));
}
// Referansı silerek GC'yi (Gri ani yükseliş) zorla
setTimeout(() => {
gcMemoryStore = [];
document.getElementById("system-status").innerText =
"Referanslar silindi. GC bekleniyor (Gri)";
}, 1000);
}
🧭 Opsiyonel Okuma Notu
Bilgilendirme: Bu bölüm, konuların arka planına ve düşünsel temellerine daha derin bir bakış sunmak amacıyla hazırlanmıştır.
- Matematiksel, tarihsel ve felsefî içerikler isteğe bağlı olarak okunabilir.
- Her bölümün içerik seviyesi ve yoğunluğu farklılık gösterebilir.
- Temel düzey kullanıcılar için zorunlu değildir, ileri düzey okuma niteliğindedir.
Bellek Yönetiminin Felsefi ve Teknik Temelleri
JavaScript motorlarının (V8, SpiderMonkey) belleği neden ve nasıl iki ana bölüme (Stack ve Heap) ayırdığını, otomatik Çöp Toplama (GC) mekanizmasının tarihsel zorunluluğunu ve bu otomasyonun yarattığı bellek sızıntısı risklerini mimari düzeyde inceleyin.
Bellek Yönetiminin Temelleri Yığın (Stack) ve Öbek (Heap) Mimarisi
Bellek Yönetimi, bir yazılımın donanım kaynaklarını en verimli şekilde kullanma sanatıdır.
Bir uygulamanın performansı ve uzun vadeli kararlılığı, verilerin belleğe nasıl yerleştiği ve işi bittiğinde orayı nasıl terk ettiğiyle doğrudan ilişkilidir.
Programlamada bellek, türü ne olursa olsun üç temel aşamadan oluşan evrensel bir yaşam döngüsünü takip eder:
1. Tahsis (Allocation) JavaScript motoru, kodunuzda bir değişken tanımladığınız anda ( const x = 10; gibi ) devreye girer.
Verinin türüne göre ( ilkel veya referans ), işletim sisteminden bu bilgiyi saklamak için otomatik olarak uygun büyüklükte bir yer talep eder ve ayırır.
2. Kullanım (Usage) Bu aşama, bellekteki verinin aktif olduğu "çalışma zamanı"dır.
Kodunuz değişkenleri okur, nesne özelliklerini günceller veya fonksiyonlara parametre olarak gönderir.
Bellek, programın mantığını yürütmek için gereken ham bilgiyi sağlar.
3. Serbest Bırakma (Release) İhtiyaç duyulmayan verinin belleği terk etmesi aşamasıdır.
C veya C++ gibi dillerde bu adım geliştiricinin manuel sorumluluğundadır.
JavaScript'te ise bu yük geliştiricinin üzerinden alınmış olsa da, mantıksal hatalar bu adımın gerçekleşmesini engelleyebilir.
Otomatik Yönetim ve Gizli Sızıntı RiskiJavaScript, bellek serbest bırakma sürecini Çöp Toplama mekanizmasıyla otomatikleştirir.
Bu otomasyon büyük bir konfor sağlasa da, geliştiricileri "yanıltıcı bir güvenlik" hissine sokabilir.
Erişilebilirlik Yanılsaması: Eğer bir nesneye olan referansı kodunuzda yanlışlıkla tutmaya devam ederseniz, Çöp Toplayıcı o nesneyi hala "erişilebilir" ve "gerekli" zanneder.
Sonuç olarak, bellek serbest bırakılamaz; bu da uygulamanın zamanla ağırlaşmasına, takılmasına ve sonunda çökmesine neden olan
Bellek Sızıntısı problemini doğurur.
JavaScript'in perde arkasında nasıl bellek tahsis ettiğini ve hangi veriyi nereye koyduğunu anlamak, sızıntısız ve yüksek performanslı uygulamalar geliştirmenin en temel şartıdır.
Bellek Havuzları Yığın (Stack) ve Öbek (Heap)
JavaScript motorları, verimliliği maksimize etmek için belleği iki temel havuza ayırır: Yığın ve Öbek.
Bu ayrım rastgele bir tercih değil; verinin boyutuna, karmaşıklığına ve bellekte ne kadar süre kalacağına göre verilen stratejik bir karardır.
Bu iki yapı, modern işlemci mimarisinin hızını ve esnekliğini bir araya getirir.
1. Yığın (Stack): Statik ve HızlıHızın Merkezi: Stack, "Son Giren İlk Çıkar" ( LIFO ) mantığıyla çalışan, inanılmaz derecede hızlı bir bellek bölgesidir.
Burada boyutu önceden bilinen ve sabit olan veriler ( İlkel tipler: number, string,boolean , null, undefined ) depolanır.
Otomatik Yönetim: Stack üzerindeki veriler, bulundukları fonksiyonun yürütülmesi tamamlandığı anda sistem tarafından otomatik ve anında temizlenir.
Bu bölge, Çöp Toplayıcı'nın müdahalesine gerek kalmadan kendi kendini yöneten statik bir alandır.
2. Öbek (Heap): Dinamik ve EsnekEsnekliğin Alanı: Heap, boyutu çalışma anında değişebilen ve karmaşık veri yapılarına ( Nesneler , Diziler , Fonksiyonlar ) ev sahipliği yapan çok daha geniş bir bellek bölgesidir. Stack'in aksine veriler burada dağınık ve dinamik olarak yerleştirilir.
GC'nin Çalışma Sahası: Heap, JavaScript'in Çöp Toplayıcı mekanizmasının ana operasyon bölgesidir.
Buradaki verilerin ne zaman serbest bırakılacağı, Stack'teki gibi fonksiyon bitişine değil, o veriye olan referansların ( bağlantıların ) kesilip kesilmediğine bağlıdır.
Köprü Kurmak: Referanslı BağlantıBu iki havuz birbiriyle sürekli iletişim halindedir. Bir nesne oluşturduğunuzda, nesnenin gerçek verisi Heap'te saklanırken, bu veriye erişimi sağlayan "adres" bilgisi (pointer) Stack'te tutulur.
Bellek sızıntıları genellikle bu adreslerin Stack'ten veya global kapsamdan temizlenmemesi sonucu, Heap'teki verinin sahipsiz ama "canlı" kalmasıyla oluşur.
Sonuç olarak Stack ve Heap mimarisi, JavaScript'in hem hızlı ( statik verilerle ) hem de yetenekli ( karmaşık nesnelerle ) olmasını sağlar.
Bellek yönetimi disiplini, bu iki havuz arasındaki dengeyi korumak ve Heap bölgesini gereksiz işgallerden arındırmaktır.
Yığın (Stack) Mimarisi Hızlı ve Sıralı Yönetim
Yığın, JavaScript motorunun en düzenli, en hızlı ve en disiplinli bellek bölgesidir.
Adından da anlaşılacağı gibi, veriler buraya üst üste dizilen tabaklar veya bir kutuya yerleştirilen kitaplar gibi sıralı bir şekilde yerleştirilir.
Stack, bilgisayar bilimlerinin temel prensiplerinden biri olan LIFO ( Last-In, First-Out / Son Giren İlk Çıkar ) mantığıyla çalışır.
Bu yapı, veriye erişim hızını maksimize ederken bellek yönetimini bir otomatizmaya dönüştürür.
İçeriği: Sabit Boyutlu Verilerin EviStack, "boyutu önceden bilinen" veriler için tasarlanmıştır, bu bölgede saklanan her bir birimin ne kadar yer kaplayacağı derleme veya başlangıç aşamasında bellidir.
İlkel (Primitive) Değerler: number, boolean, null, undefined ve string gibi değerler Stack'te depolanır.
Ayrıca, fonksiyon çağrıları sırasında oluşturulan fonksiyon çerçeveleri ve bu fonksiyonlara ait yerel değişkenler de burada tutulur.
Veriler küçük ve sabit boyutlu olduğu için Stack üzerinde işlem yapmak işlemci için maliyetsizdir.
Otomatik Yönetim: "Çağrı Yığını" DinamiğiKendini Temizleyen Sistem: Stack yönetiminin en büyük avantajı tam otomatize olmasıdır.
Bir fonksiyon çağrıldığında, o fonksiyona özel bir alan Stack'in en üstüne eklenir.
Fonksiyon çalışmasını bitirip return ettiğinde, o alan ve içindeki tüm yerel değişkenler anında Stack'ten atılır.
Bu işlem için Çöp Toplayıcı'nın gelip analiz yapmasına gerek yoktur; bellek serbest bırakma işlemi donanımsal bir hızla gerçekleşir.
Sınırlamalar ve PerformansStack alanı kısıtlıdır, eğer bir fonksiyon kendini sonsuz kez çağırırsa ( hatalı özyineleme ), Stack dolar ve meşhur "Stack Overflow" hatası meydana gelir.
Bu nedenle, sadece kısa ömürlü ve boyutu net olan veriler buraya emanet edilir.
Tüm bunların sonucunda Yığın mimarisi, JavaScript'in günlük yürütme hızının temel motorudur.
Karmaşık nesnelerle uğraşmadan önce, basit değerlerin bu sıralı ve hızlı yolda nasıl yönetildiğini anlamak, bellek yönetiminin ilk basamağıdır.
Öbek (Heap) Mimarisi Dinamik ve Karmaşık Yönetim
Öbek, JavaScript belleğinin en geniş, en esnek ve aynı zamanda en düzensiz bölgesidir.
Sabit ve sıralı olan Stack'in aksine Heap, verilerin çalışma zamanında dinamik olarak yerleştirildiği devasa bir depolama alanı gibidir.
Bir nesnenin veya dizinin ne kadar büyüyeceği önceden kestirilemediği için, JavaScript motoru bu tür yapılar için Heap bölgesinden yer ayırır.
Burası, verilerin kutulara hiyerarşik dizildiği bir kütüphaneden ziyade, her yeni gelen eşya için uygun bir boşluk bulunan geniş bir depo gibidir.
İçeriği: Referans Tiplerinin DünyasıReferans (Reference) Tipleri: Heap; nesneler, diziler ve fonksiyonlar gibi karmaşık yapıların evidir.
Bu yapılar "değişebilir" karakterdedir; yani içlerine yeni özellikler eklenebilir veya boyutları artırılabilir.
Adresleme Mekanizması: Önemli bir ayrım şudur: Karmaşık veri Heap'te yaşarken, ona nasıl ulaşılacağını söyleyen referans bilgisi
Stack'te saklanır.
Kodunuzda bir nesneye eriştiğinizde, JavaScript aslında Stack'teki adresi okur ve o adresin işaret ettiği Heap bölgesindeki gerçek veriye gider.
Yönetimi: Çöp Toplayıcının (GC) Görev AlanıKarmaşık Denetim: Heap üzerindeki veriler, Stack'teki gibi fonksiyon bittiğinde otomatik olarak silinmez.
Bir nesnenin işinin ne zaman bittiği belirsiz olduğundan, bu bölgenin temizliği Çöp Toplayıcı tarafından üstlenilir.
Performans Maliyeti: GC, Heap'i sürekli tarayarak hangi nesnelere hala ulaşılabildiğini kontrol eder.
Bu tarama işlemi, Stack'in anlık temizliğine göre çok daha fazla CPU kaynağı tüketir ve daha karmaşıktır.
Bu nedenle, Heap'i gereksiz ve devasa verilerle doldurmak, uygulamanın performansını doğrudan etkileyen bir unsurdur.
Sonuç olarak Öbek mimarisi, JavaScript'e modern uygulamalar için gereken dinamik gücü verir.
Ancak bu esneklik, bellek sızıntılarına açık bir zemin hazırladığı için, referansların doğru yönetilmesi ve GC'nin iş yükünün hafifletilmesi profesyonel kod yazımının temelidir.
Referans Tipleri ve Değer Tipleri Arasındaki Teknik Fark Genel Bilgi
JavaScript'te verilerin Yığın ve Öbek arasında dağıtılmasının ana nedeni, verinin doğası gereği nasıl taşındığıyla ilgilidir.
Bu teknik ayrım, kodun çalışma anındaki davranışlarını belirleyen en temel kuraldır.
Değişken atamaları, fonksiyonlara parametre gönderme ve verileri karşılaştırma süreçleri, verinin bir "değer" mi yoksa bir "referans" mı olduğuna göre tamamen farklı yollar izler.
1. Değer Tipleri (Value Types): Stack'teki BağımsızlıkDoğrudan Kopyalama: İlkel veri tipleri Stack üzerinde "değer" olarak saklanır.
Bir ilkel değişkeni başka bir değişkene atadığınızda ( let a = 5; let b = a; gibi ), JavaScript verinin tam bir kopyasını oluşturur.
Değişmezlik (Immutability): Bu yapı, veriler arasında tam bir bağımsızlık sağlar.
b üzerinde yapılan bir değişiklik asla a'yı etkilemez.
Her değişken kendi küçük hücresinde, kendi değerini kimseye hesap vermeden saklar, bu durum, beklenmedik yan etkilerin önüne geçer.
2. Referans Tipleri (Reference Types): Heap'teki OrtaklıkAdres Paylaşımı: Nesneler, diziler ve fonksiyonlar ise Heap üzerinde saklanır.
Bir nesneyi başka bir değişkene atadığınızda, nesnenin verisi kopyalanmaz; sadece o veriye giden "referans" kopyalanır.
Mutasyon ve Yan Etkiler: İki farklı değişken aynı bellek adresini işaret ettiği için, bir değişken üzerinden nesnenin bir özelliğini değiştirdiğinizde, diğer değişken de bu değişikliği görür, çünkü her iki değişken de Heap'teki aynı fiziksel veriye bakmaktadır.
Bu, nesnelerin "ortak sahip olunan" ( shared ownership ) bir yapıda olduğunu gösterir.
Karşılaştırma Mantığı: Eşitlik TestiDeğer vs Adres: İlkel tipler içeriklerinebvgsörevkarşılaştırılır ( 5 === 5 ).
Ancak referans tipleri, içerikleri aynı olsa bile bellek adreslerine göre karşılaştırılır.
İki farklı boş nesne ( {} === {} ) asla birbirine eşit değildir, çünkü her biri Heap üzerinde farklı adreslerde oluşturulmuştur.
Sonuç olarak, bu ayrımı kavramak, JavaScript'teki "garip" davranışların çoğunu açıklar. İ
lkel verilerin güvenli ve bağımsız dünyası ile nesnelerin esnek ama dikkat gerektiren ortak dünyası arasındaki dengeyi kurmak,
hatasız ve optimize edilmiş bir kod mimarisinin ilk kuralıdır.
Değer Tipleri (Primitives) Sabit ve İmutabil
Değer Tipleri (Primitives): JavaScript'in en temel yapı taşlarıdır ve doğrudan verinin kendisini temsil ederler.
Bir nesne gibi dallanıp budaklanmazlar; sadece tek bir değeri tutarlar.
JavaScript evreninde string, number, boolean, null, undefined, Symbol ve BigInt bu gruba dahildir. Bu tiplerin ortak özelliği, oluşturulduktan sonra içeriklerinin asla değiştirilemez olmasıdır.
Depolama: Stack Üzerindeki Hızlı ErişimStatik ve Tahmin Edilebilir: Değer tipleri, bellekte ne kadar yer kaplayacakları ( bir sayının kapladığı bit miktarı gibi ) önceden belli olduğu için Yığın üzerinde depolanır.
Stack'in sıralı ve hızlı erişim yeteneği sayesinde, bu değişkenlere ulaşmak ve üzerlerinde işlem yapmak milisaniyenin çok altında bir maliyetle gerçekleşir, bu hız, JavaScript'in günlük hesaplama performansının temelidir.
Kopyalama Davranışı: Tam İzolasyonBağımsız Kopyalar: Bir değer tipini başka bir değişkene atadığınızda ( let x = 10; let y = x; ), JavaScript x'in değerini alır ve y için Stack'te yeni bir hücre açarak oraya kopyalar.
Artık x ve y tamamen farklı dünyaların insanlarıdır.
Yan Etkisiz Kod (Pure Logic): y değerini değiştirdiğinizde ( y = 20; ), orijinal olan x bu durumdan hiç haberdar olmaz.
Bu izolasyon, kodun içinde "beklenmedik yan etkilerin" oluşmasını engeller ve programın mantığını çok daha güvenli hale getirir.
Eşitlik Kontrolü: İçerik KıyaslamasıGerçek Karşılaştırma: Değer tiplerinde sıkı eşitlik kontrolü ( === ) yapıldığında, JavaScript sadece Stack'teki hücrelerin içeriğine bakar.
Eğer iki hücredeki değer bit seviyesinde aynıysa ( "merhaba" === "merhaba" ), sonuç true döner ve bu, referans tiplerindeki
"adres karşılaştırması" karmaşasından tamamen uzaktır.
Sonuç olarak Değer Tipleri; hız, bellek verimliliği ve değişmezlik sunar.
Kodunuzun temellerini bu basit ama sağlam yapılar üzerine inşa etmek, karmaşık uygulamalarda bile verinin doğruluğundan emin olmanızı sağlar.
Referans Tipleri (Objects) Sabit ve İmutabil
Referans Tipleri, JavaScript'te verinin kendisini değil, o verinin bellekte "nerede" olduğunu temsil eden yapılardır.
İlkel tiplerin aksine; nesneler, diziler, fonksiyonlar ve Date, RegExp gibi yerleşik yapılar bu kategoriye girer.
Bu veriler dinamik bir doğaya sahiptir; yani program çalışırken büyüyebilir, küçülebilir veya içerikleri karmaşıklaşabilir.
Depolama: İki Bölge Arasındaki KöprüHiyerarşik Yerleşim: Referans tiplerinin yönetimi, JavaScript belleğinin her iki bölgesini de kullanır:
Öbek (Heap): Nesnenin asıl içeriği, boyutunun belirsizliği nedeniyle bu geniş ve esnek alanda depolanır.
Yığın (Stack): Değişkenin kendisi ise sadece bu devasa Heap alanındaki veriye giden bellek adresini tutar.
Stack'teki bu adres, bir harita üzerindeki konum bilgisi gibidir; sizi gerçek hazineye (veriye) ulaştırır.
Kopyalama Davranışı: Ortak Sahiplik (Mutability)Adres Paylaşımı: Bir nesneyi başka bir değişkene atadığınızda ( let obj1 = { puan: 10 }; let obj2 = obj1; ), nesnenin kendisi kopyalanmaz.
Sadece obj1'in elindeki "adres" kopyalanarak obj2'ye verilir.
Yan Etkiler ve Mutasyon: Artık her iki değişken de Heap'teki aynı fiziksel veriye bakmaktadır.
Dolayısıyla obj2 üzerinden yapılan bir güncelleme, obj1'i de anında etkiler.
Çünkü değişen şey bir kopya değil, her iki referansın da işaret ettiği ortak "ana kaynaktır".
Bu durum, referans tiplerinin mutable (değişebilir) doğasının temelidir.
Eşitlik Kontrolü: Kimlik SorgusuAdres mi, Değer mi? Referans tiplerinde === kontrolü yapıldığında, JavaScript nesnelerin içindeki verilere bakmaz.
Sadece Stack'teki bellek adreslerinin aynı olup olmadığını kontrol eder.
İlginç Sonuç: İçerikleri tıpatıp aynı olsa bile, farklı zamanlarda oluşturulmuş iki farklı nesne ( {} === {} ) false döner.
Çünkü her biri Heap üzerinde farklı "arazilere" yerleşmiştir ve adresleri farklıdır.
Özet ile Referans Tipleri, büyük verileri kopyalama maliyetine girmeden yönetmemizi sağlar.
Ancak "aynı adrese bakma" durumu, dikkatsiz kodlarda beklenmedik veri değişikliklerine yol açabilir.
Bu mimariyi anlamak, özellikle modern framework'lerde ( React vb.) verinin değişip değişmediğini kontrol ederken hayati bir fark yaratır.
const sayi = 10; // Stack
const metin = 'Merhaba'; // Stack
const bool = true; // Stack
İlkel (Primitive) değerler Stack bellekte saklanır ve doğrudan değeri taşırlar.
Bu nedenle kopyalandıklarında değerleri çoğaltılır, referans paylaşılmaz.
const obje = {}; // Heap
const dizi = []; // Heap
const func = function() {}; // Heap
Referans tipleri Heap bellekte saklanır ve değişken sadece referans (adres) tutar.
Bu yüzden kopyalandıklarında aynı veriyi paylaşırlar.
let a = 10;
let b = a; // Değer kopyalanır
b = 20; // a değişmez
Primitive değerler kopyalandığında her değişken kendi değerinin bir kopyasına sahip olur; biri
değiştiğinde diğeri
etkilenmez.
let obj1 = { x: 1 };
let obj2 = obj1; // Referans kopyalanır
obj2.x = 2; // obj1.x de değişir
Nesneler referans olarak kopyalanır
const weakMap = new WeakMap();
const obj = {};
weakMap.set(obj, 'metadata');
weakMap.get(obj); // 'metadata'
WeakMap sadece nesneleri anahtar olarak tutar ve referansı kaybolan nesneler otomatik olarak
bellekten temizlenir
(garbage collection).
const weakSet = new WeakSet();
const element = document.querySelector('div');
weakSet.add(element);
weakSet.has(element); // true
WeakSet yalnızca nesne referansları tutar ve referansı silinen nesneler otomatik olarak bellekten
temizlenir.
weakMap.delete(obj); // Manuel silme
WeakMap’te bir anahtarın referansını manuel olarak kaldırmak için
delete() kullanılır.
const worker = new Worker('worker.js');
Worker, ana iş parçacığından bağımsız çalışarak CPU yoğun işlemleri
arka planda yürütür ve performansı artırır.
worker.postMessage(data);
worker.postMessage(data, [transferableObj]);
PostMessage ile ana thread ve worker arasında veri gönderilir; transferable kullanıldığında bellek
kopyalanmadan
sahipliği devredilir.
worker.onmessage = function(e) {
const sonuc = e.data;
};
Worker’dan gelen veriyi dinleyerek sonucu işlememizi sağlar.
worker.terminate(); // Worker'ı sonlandırır
Çalışmakta olan worker’ı durdurarak sistem kaynaklarını serbest bırakır.
const timerId = setTimeout(() => {
console.log('Tek seferlik');
}, 1000);
Belirli bir süre sonra yalnızca bir kez çalışan zamanlayıcı
oluşturur.
const intervalId = setInterval(() => {
console.log('Tekrarlı');
}, 1000);
Belirtilen aralıklarla tekrar tekrar çalışan zamanlayıcıdır.
clearTimeout(timerId); // Zamanlayıcıyı iptal eder
ClearTimeout, setTimeout ile kurulan zamanlayıcıyı çalışmadan önce iptal eder.
clearInterval(intervalId); // Interval'ı iptal eder
ClearInterval, setInterval ile başlatılan tekrar eden zamanlayıcıyı
durdurur.
element.addEventListener('click', handler);
Bir elemente olay dinleyicisi ekleyerek etkileşimleri
yakalar.
element.removeEventListener('click', handler);
RemoveEventListener, eklenen olay dinleyicisini kaldırarak olayı dinlemeyi durdurur.
element.addEventListener('click', handler, {
once: true
});
Once seçeneği, olay dinleyicisinin yalnızca bir kez çalışmasını sağlar ve otomatik olarak
sistemden kaldırılır.
const start = performance.now();
// Kod çalışır
const end = performance.now();
const sure = end - start; // Milisaniye
Performance.now, yüksek çözünürlüklü zaman ölçümü yaparak kodun çalışma süresini hassas şekilde
hesaplar.
performance.mark('baslangic');
performance.mark('bitis');
performance.measure('sure', 'baslangic', 'bitis');
Performance.mark, zaman damgaları oluşturarak belirli kod bölümlerinin performansını ölçmeye imkân
sağlar.
const memory = performance.memory;
console.log(memory.usedJSHeapSize); // Kullanılan bellek
Performance.memory, Chrome geliştirici araçlarında bellek kullanımını kontrol etmek için
kullanılır.
let buyukObje = { data: new Array(1000000) };
buyukObje = null; // GC'nin toplamasına izin verir
Referansın null yapılması, nesnenin artık kullanılmadığını gösterir ve Garbage Collector’ın
belleği temizlemesine izin
verir.
'use strict'; // Kasıtsız global'ları önler
let degisken = 10; // Doğru kullanım
'Use Strict', tanımlanmamış değişkenlerin global oluşmasını engelleyerek daha güvenli bellek
yönetimi sağlar.
Öğrenme Yolu
JavaScript öğrenme yolculuğunuzda neredesiniz?
Bu bölüm, JavaScript öğrenme yolculuğunuzdaki ilerlemenizi görselleştirir. Aşağıda göreceğiniz adımlar, konular arasındaki mantıksal sıralamayı ve öğrenme akışını temsil eder. Tamamlanan konular mavi tonlarda gösterilir ve üzerinde bir onay işareti bulunur. Aktif konu, şu anda üzerinde çalıştığınız bölümdür ve parlak mavi renkle vurgulanır. Sonraki adımlar ise henüz tamamlanmamış konuları gösterir ve daha soluk tonlarda görüntülenir.
Her adım arasındaki oklar, öğrenme sırasını ve konular arasındaki bağlantıyı gösterir. Bu yapı, hangi konuları tamamladığınızı, hangi konuda olduğunuzu ve sıradaki adımlarınızı net bir şekilde görmenizi sağlar.
Modülerlik ve Kod Organizasyonu
ES Modülleri, Bağımlılık Enjeksiyonu ve IoC Konteynerleri
Performance ve Memory
Performans optimizasyonu ve bellek yönetimi