“Call Stack” Kavramı Nedir?
Bu yazımızda, programlama dünyasında sıkça duyulan ve önemli bir kavram olan “call stack” kavramı nedir sorusuna cevap vereceğiz.
“Call Stack” Nedir?
“Call Stack”, Türkçede genellikle “çağrı yığını” olarak adlandırılır, ancak bu terim bilgisayar bilimleri bağlamında daha derin bir anlam taşır ve bir programın, fonksiyon çağrılarını izlemek için kullandığı bir yapı olarak işlev kazanır.
Bu yapı, fonksiyonların hangi sırayla çalıştırıldığı, hangi fonksiyonun şu anda çalıştığı ve fonksiyonların nereden çağrıldığı gibi bilgileri saklar. LIFO (Last In, First Out – Son Giren İlk Çıkar) mantığına dayanan çalışma prensibine sahip olması nedeniyle son çağrılan fonksiyonun ilk tamamlanan fonksiyondur.
Bu terimi daha somut bir şekilde anlamak için alışverişe gidip aldığınız ürünleri poşete koyma eylemine benzetebiliriz.
Alışverişe gittiğinizde, raf üzerinden aldığınız ürünleri sırayla alışveriş poşetinize koyarsınız. İlk aldığınız ürün poşetin dibinde kalırken, en son aldığınız ürün poşetin üstünde olur. Eğer evde bu ürünleri poşetten çıkarmaya başlarsanız, ilk çıkaracağınız ürün en son aldığınız ürün olacaktır. Yani, poşetten çıkarma işlemi, ürünleri koyduğunuz sıranın tam tersi olur.
İşte “Call Stack” de aynı bu alışveriş poşeti mantığıyla çalışır. Fonksiyonlar çağrıldıkça “stack’in” üstüne eklenir ve tamamlandıkça üstten çıkarılır.
JavaScript’te “Call Stack” Kullanımı
Bir fonksiyon çağrıldığında, Call Stack’in en üstüne eklenir. Bu fonksiyon tamamlandığında, yani tüm görevlerini tamamladığında, Call Stack’ten çıkarılır. Eğer bir fonksiyon içinde başka bir fonksiyon çağrılırsa, bu yeni fonksiyon mevcut fonksiyonun üstüne eklenir ve en son eklenen fonksiyon öncelikle tamamlanır.
Bilindiği üzere JavaScript single-thread (tek iş parçacıklı) bir dil olduğundan tek bir “call stack” olmakta ve aynı anda sadece tek bir iş yapabilmektedir. Bu özellik, JavaScript’in çalışma şeklini doğrudan etkiler.
Zira aynı anda yalnızca bir fonksiyon işlenebilir ve diğer fonksiyonlar onun tamamlanmasını beklemek zorundadır. Bu da, fonksiyonların ne zaman ve nasıl işleneceğinin, kodun yazıldığı sıra ve fonksiyonların birbirlerini nasıl çağırdığına bağlı olduğu anlamına gelmektedir.
Örneğin, bir fonksiyonA()
içinde fonksiyonB()
çağrılırsa; ilk olarak fonksiyonA()
Call Stack’e eklenir. Ardından fonksiyonB()
çağrıldığında, bu fonksiyon Call Stack’in en üstüne gelir. fonksiyonB()
tamamlandığında Call Stack’ten çıkar ve sıra fonksiyonA()
‘ya gelir.
Yani her bir fonksiyon çağrısı, çağıran fonksiyonun call stack içindeki bir üstüne yerleştirilir ve oradan çalıştırılır. Bu işlem, programın çalıştığı süre boyunca devam eder. Fonksiyon sona erdiğinde ise call stack’ten çıkarılır ve kontrol tekrar ilk olarak çağrılan fonksiyona döner.
function add(a, b) {
return a + b;
}
function average(a, b) {
return add(a, b) / 2;
}
let ave = average(10, 20);
Yukarıdaki örneğimizde ilk olarak main()
fonksiyonu çalışacak onun da ardından average()
fonskiyonu döndürülecektir. Son olarak ise add()
fonskiyonu çalıştırılacaktır. İşlem bittikten sonra ise son çağrılan add()
ilk olarak “call stack’ten” çıkartılacak. Bu şekilde son sıradan ilk sıraya işi biten stack’ten çıkarıtılacaktır.
Ancak burada dikkat edilmesi gereken önemli bir husus vardır; “call stack”, sınırlı bir kapasiteye sahiptir. Eklenen her fonksiyon çağrısı, bellekte bir stack oluşturarak depolanır. Eğer “call stack’e” eklenen fonksiyon çağrısı sayısı artar ve bellek yığınının kapasitesini aşarsa “stack overflow” hatası meydana gelir.
Bu hatanın nedeni, programın çalışma zamanında çağrılan fonksiyonların çok fazla bellek kullanmasıdır. Tahmin edeceğiniz üzere, yazılım geliştirme topluluğunun önemli bir kaynağı ve programlama konularında pek çok soru-cevap ve öğretici içerikler içeren Stack Overflow sitesi, “stack overflow” hatasından esinlenerek kurulmuştur.