C#’ta Gösterici(Pointer) – stackalloc Anahtar Sözcüğü – IX

Merhaba,

Bir önceki C#’ta Gösterici(Pointer) – Göstericiler İle Dizi İşlemleri – VIII başlıklı makalemizde göstericiler ile dizi işlemlerini fixed keywordü ile ele almıştık. Bu içeriğimizde ise önceki makalemizle içerik açısından paralel doğrultuda olan ama yapısal ve yaklaşım olarak oldukça farklılık arz eden stackalloc anahtar sözcüğü üzerine konuşuyor olacağız.

stackalloc Anahtar Sözcüğü Nedir? Ne İşe Yarar?

C programlama dilindeki alloce deyimine karşılık gelen stackalloc keywordü CLR(Common Language Runtime)’a belleğin stack bölgesinde yer ayırtmasını sağlamaktadır.

Örneğin; aşağıdaki kod bloğunu incelerseniz eğer stackalloc keywordü sayesinde belleğin stack kısmında int tipinde 3 adet(3 x 4 = 12 bytelık) yer ayırtmaktadır.

            unsafe
            {
                int* Pointer = stackalloc int[3];
            }

Bu şekilde yapılan bir tanımlama sayesinde yukarıda da bahsedildiği üzere belleğin stack kısmında int tipinden 3 x 4 = 12 bytelık bir alan ardışıl olarak ayrılmıştır. Burada bilmeniz gereken “Pointer” isimli göstericimiz ayrılan alanlardan ilk olanı temsil etmektedir. Bu demek oluyor ki, göstericimize “+= 1” diyerek aritmatik bir işlem sonucu sonraki alanlara erişebiliriz.

Haliyle stackalloc deyimi bizleri fixed keywordünü kullanmaktan kurtarmaktadır. Nihayetinde fixed keywordü nesnelerin üye elemanlarının garbage collector mekanizması sayesinde bellek adreslerinin değiştirilmemesi için bir sabitleyici görevi almaktaydı. İşte bu yüzden yukarıda linkini vermiş olduğum bir önceki göstericiler ile dizilerin kullanımına değindiğimiz makalemizde dizilerin belleğin heap bölgesinde oluşturulduğundan bahsederek, System.Array sınıfının bir üyeleri olmalarından dolayı fixed keywordü ile üzerlerinde çalışmaktaydık. stackalloc keywordü ise diziyi belleğin heap bölgesinde değil stack bölgesinde oluşturmamızı sağlamakta ve unmanaged type(yönetilmeyen tip) olarak çalışmamızı sürdürebilmekteyiz.

Peki stackalloc Anahtar Sözcüğünü Neden Tercih Ederiz?

Managed type(yönetilen tip)’de çalışmak unmanaged type’de çalışmaktan her ne kadar kolay ve kullanışlı olsada bazı durumlarda performans eksiklikleri söz konusudur. Mesela, belleğin heap kısmında tanımlanmış ve System.Array sınıfından türemiş bir dizinin elemanlarına ulaşmakla, stack kısmında tanımlanmış bir dizinin elemanlarına erişmek arasında zaman ve maliyet açısından oldukça fark vardır.

Belleğin stack kısmında stackalloc keywordü ile üretilen diziler unmanaged type dizilerdir.

Göstericiler söz konusu olduğunda her ne kadar olası hatalar söz konusu olsada aynı durum belleğin stack kısmında oluşturulmuş diziler içinde geçerli olacaktır. Nihayetinde işaretçiler işin içindedir ve bu dizileri kullanırken oldukça dikkatli olmamız gerekmektedir.

Peki hoca, nasıl durumlara karşı dikkatli olmamız gerekmektedir? diye sorabilirsiniz… Şöyle düşünün… Managed type dizilerde sınırlar aşıldığı zaman hata alıyoruz değil mi? Unmanaged type dizilerde ise sınır kavramı bulunmamaktadır. Bunun sebebi ilgili dizinin elemanları işaretçiler ile ifade edileceği için sınır kavramı olmayacaktır. Stack’te ki bir dizinin sınırını aştığımız zaman bize tahsis edilmeyen bellek alanlarına ulaşmış olacağız. Tabi bu alanlar koruma altındaysalar olası hatalar verebilirler. Bunun dışında bilinçsiz bir şekilde bilmediğimiz alanlara erişmiş bulunacağız ama her zaman hata almayacağız. Özellikle dizinin sınırlarını aştığımız için kesinlikle hata almayacağız…

Şimdi gelin belleğin stack kısmında bir dizi oluşturalım.

            unsafe
            {
                int* dizi = stackalloc int[3]; // Belleğin stack kısmında 3 x 4 = 12 byte'lık alan ayrıldı.
                for (int i = 0; i < 3; i++)
                {
                    *(dizi + i) = i + 10;
                    Console.WriteLine(*(dizi + i));
                }
            }

Görüldüğü üzere belleğin stack kısmında stackalloc keywordü ile bu şekilde dizi oluşturulmaktadır. “dizi” referansı ilk olarak oluşturulan bellek alanlarının ilkini temsil etmektedir.

Yukarı satırlarda bahsetmiş olduğumuz stack’te ki dizilerin sınır kavramı olmadığını aşağıdaki kod bloğu sayesinde daha net bir şekilde görmekteyiz.

            unsafe
            {
                int* dizi = stackalloc int[3]; // Belleğin stack kısmında 3 x 4 = 12 byte'lık alan ayrıldı.
                for (int i = 0; i < 10; i++)
                {
                    *(dizi + i) = i + 10;
                    Console.WriteLine(*(dizi + i));
                }
            }

Dikkat ederseniz dizimiz 3 elemanlıdır lakin for döngüsünde 10 kez tur düzenlenmiştir. Yapılan işlemler neticesinde ilgili dizinin sınırı teorik olarak aşılmış olsada bir sınır aşılmaya dair kesin bir hata söz konusu olmayacaktır.

stackalloc anahtar sözcüğü ile tahsis edilen bellek alanlarının ardışıl olması garanti altına alınmış olur.

Şimdi farklı bir noktaya değinmek için aşağıdaki başlangıç aşamasından olan kod bloğunu yeniden ele alalım.

            unsafe
            {
                int* dizi = stackalloc int[3];
            }

stackalloc keywordü ile belleğin stack kısmında 3 adet int tipinde 12 byte’lık alan ayırmış olduk. Bunu biliyoruz. Ancak bu ayrılan alanların içeriklerinde neler var bilmiyoruz. Bu ayrılan bellek adreslerinin içerisinde rastgele verilerin/değerlerin bulunduğu 12 byte’lık bir alandan bahsedebiliriz.

Bunu aşağıdaki şu örnekle daha net görebiliriz.

            unsafe
            {
                int* dizi = stackalloc int[15];
                for (int i = 0; i < 15; i++)
                    Console.WriteLine($"{i}. eleman değeri : {*(dizi + i)}");
            }

C#’ta Gösterici(Pointer) – stackalloc Anahtar Sözcüğü – IX

Buradaki değerler ayrılan alanlardaki rastgele değerlerdir. Tabi ki de sizler farklı sonuçlar alabilirsiniz. Ben ilgili projeyi derleyip çalıştırdığım an bu değerler ayrılan alanlarda var olduğu için yazdırılmıştır. Farklı bir zamanda farklı değerlerle karşılaşmamız olağandır.

Göstericilerle ilgili bir yazımızın daha sonuna gelmiş bulunmaktayız. Bir sonraki içeriğimizde göstericilerde indexer kullanımını inceleyeceğiz.

Sonraki yazılarımda görüşmek üzere…
İyi çalışmalar…

Bunlar da hoşunuza gidebilir...

4 Cevaplar

  1. Umut dedi ki:

    Merhaba. Öğrenciyim. Yazılarınız çok yardımcı oluyor. Çok anlaşılır anlatıyorsunuz. Elinize sağlık.

  1. 09 Ocak 2019

    […] C#’ta Gösterici(Pointer) – stackalloc Anahtar Sözcüğü – IX […]

  2. 21 Haziran 2020

    […] managed bölgesi olan HEAP’de tutulmakta, bunu STACK’te gerçekleştirebilmek için ise stackalloc keywordünden yararlanılmaktadır. Bu bilgiler ışığında Span, stack yahut heap farketmeksizin […]

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

*