okanvikişisel web güncesi

Bellek Yönetimi İncelikleri

10 Aralık 2023 tarihinde yayınlandı~3 dakika okuma süresi

Herhangi bir programlama dili için bellek yönetimi en önemli konulardan biridir. Bu yazıda, bellekte veri saklamanın kötü pratiklerini ve olası iyileştirmeleri inceleyeceğiz.

En temelde bellek yönetimi, bir uygulamanın çalışması sırasında belleği düzenlemeyi ve kullanılmayan alanı serbest bırakmayı konu alır. Bazı diller bellek yönetimini otomatik olarak yapan araçlar barındırırken, bazı diller de bu konuyu geliştiricinin inisiyatifine bırakmayı tercih eder. Bu işlemin otomatik olarak yapılması çoğu zaman bir avantaj olsa da, geliştirici kaynaklı bazı durumlarda uygulamaların gereğinden fazla bellek tüketmesine; hatta crash etmesine sebep olabilir.

Performans konularında en azından giriş seviyesinde bilgi sahibiyseniz, "Garbage Collection" kavramını mutlaka duymuşsunuzdur. JavaScript'te bu süreç otomatik olarak yürütülür ve artık erişilemeyen referanslar serbest bırakılarak geri alınır. Buradaki serbest bırakılmanın gerçekleştirilemediği durumlarda ise "Memory Leak" adı verilen durum oluşur.

Gelin JavaScript özelinde memory leak oluşmasına sebep olabilecek bazı durumları inceleyelim:

1 - Global Değişkenler:

function dummyFunction() {
    dummyObject = new Array(1000).fill(new Array(1000).fill(0));
}
 
dummyFunction();

Buradaki dummyObject başında let, const gibi herhangi bir tanımlayıcı olmadığı için bir global değişken haline gelir ve yukarıdaki fonksiyonun çalışması bitse bile bellekte kalmaya devam eder.

2 - Closure'lar:

function dummyFunction(element) {
    let dummyData = new Array(1000).fill(new Array(1000).fill(0));
 
    element.onclick = function() {
        // dummyData'yı kullanarak bir şeyler yap
    };
}
 
const dummyElement = document.getElementById('dummyElement')
dummyFunction(dummyElement)

Buradaki örnekte "dummyElement" id'li DOM elementinin onclick methodu içinde dummyData ile bazı işlemler yapılıyor ama sonrasında dummyData'yı temizlemek için herhangi bir işlem yapılmamış. Dolayısıyla bu element DOM'dan kaldırılsa bile dummyData bellekten kalmaya devam edecektir.

Peki buradaki problemi çözmek için ne yapılabilir?

function dummyFunction(element) {
    let dummyData = new Array(1000).fill(new Array(1000).fill(0));
 
    element.onclick = function() {
        // dummyData'yı kullanarak bir şeyler yap
    };
 
    return function cleanup() {
        element.onclick = null;
        dummyData = null;
    };
}
 
const dummyElement = document.getElementById('dummyElement');
const cleanupHandler = dummyFunction(dummyElement);
 
// Programın olağan akışı devam edebilir
 
cleanupHandler();

Görüldüğü gibi dummyFunction'ın sağladığı bir cleanup methodu yardımıyla memory leak oluşturabilecek referanslar serbest bırakılabilir.

3 - Event Listener'lar:

let element = document.getElementById('dummyElement');
element.addEventListener('click', () => {
    console.log('Clicked!');
});
 

Burada element DOM'dan kaldırılsa bile event listener bellekte kalmaya devam edebilir. Potansiyel çözüm:

let element = document.getElementById('dummyElement');
let listener = () => {
    console.log('Clicked!');
};
 
element.addEventListener('click', listener);
 
// Daha sonra
element.removeEventListener('click', listener);
listener = null;
element = null;

Buradaki gibi ilgili event listenerremoveEventListener kullanarak kaldırmak ve referansları null olarak setlemek bellekten temizlenmelerini sağlar.

Yukarıdaki başlıklar bir memory leak'e sebep olabilecek tüm durumları içermese de bu konuda fikir sahibi olmanızı sağlayacaktır. Gelin şimdi tarayıcı üzerinde bir memory leak'i nasıl tespit edebiliriz ona bakalım.

İnceleyeceğimiz örnek 2. başlığı baz alıyor kabul edelim. Yani, bir closure içindeki bir array'in içinin gereksiz datalarla dolduracağını varsayalım ve memory'e etkisini görelim.

İçerisinde dev tools barındıran modern bir tarayıcıyı açıp, ilgili araçtaki "Memory" sekmesini açıyorum:

DevTools altında "Memory" sekmesi

Burada yer alan "Take snapshot" butonuna basarak sayfanın mevcut halinin heap snapshot'ını çıkarıyorum:

Sayfanın mevcut halinin heap snapshot'ı

Artık sol taraftaki Heap Snapshots altında, sayfanın mevcut halinin memory kullanımı ile ilgili bilgiyi görebiliriz.

Sıradaki adımda, sayfadaki butona tıkladıktan sonra tekrar snapshot alacağım. Bu buton, yukarıda bahsettiğimiz array içini gereksiz data ile doldurma işlemini yapıyor olacak.

Butona tıkladıktan sonra aldığım yeni snapshot şöyle oldu:

Butona tıklandıktan sonraki heap snapshot'ı

Gördüğünüz gibi sayfanın kullandığı bellek miktarı 1.5 MB'tan 5.9 MB'a yükseldi. Kullanım sonrası ilgili alanı da temizlemediğim için buradaki dummyData array'i bellekte gereksiz yer kaplamış oldu.

Siz de kendi uygulamalarınızdaki bellek kullanımını benzer şekilde inceleyebilir ve memory leak'leri tespit edebilirsiniz.

Yazıyı burada sonlandırırken, konuyla ilgili fikir sahibi olmanıza katkı sağladığını umuyorum. Sonraki yazılarda görüşmek üzere!