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

Merhaba,

C#’ta göstericiler üzerine olan yazı dizimizin VII. makalesinde yine sizlerle beraberiz. Bu içeriğimizde göstericiler ile çalıştığımız bellek adresleri üzerinde bir koruma/sabitleme görevi görecek olan fixed anahtar sözcüğü üzerine konuşuyor olacağız.

Fixed keywordünü ele alabilmek için öncelikle teknik bilgimizi şöyle bir masaya yatırmalı ve üzerinde bir farkındalığa varmalıyız. Biliyorsunuz ki, C#’ta referans tipli değişkenler belleğin Heap bölgesinde tutulan nesneleri işaretlememizi sağlayan yapılardır. Bu değişkenler sayesinde direkt olarak nesneye erişemesekte, o nesneyi işaretlediğimiz için referans aracılığıyla erişebilmekteyiz.

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

Yukarıdaki örnek şemadan da görüldüğü üzere “x” referansı “Heap” bölgesindeki nesneyi işaretlemiş bulunmakta, haliyle “x” üzerinden nesneye erişim sağlanabilmektedir.

Şimdi burada dikkatinizi çekerim.

Gereksiz Bilgi Toplayıcı(Garbage Collector) yapısını biliyorsunuz. Bu yapı bellekteki boş gezen nesneleri yok eden bir mekanizmaya sahiptir. Ama işlevsel olarak görevi bir tek bundan ibaret değildir. Asıl görevi bellek yönetimi olduğu için bu süreçte gereken her türlü sorumluluğu üstlenmiş bir mekanizmadır. Bu sorumluluklardan biriside, bellek optimizasyonu açısından Heap bellek bölgesindeki nesnelerin yerlerini her an değiştirebilme yetkisine sahip olmasıdır.

Eğer ki Heap bellek bölgesindeki nesnelerin yerlerini değiştirirse bu değişimden biz yazılımcıların/kullanıcıların haberleri olmayacaktır. Çünkü nesnenin yeri değiştirildiği anda o nesneyi işaretleyen Stack bölgesindeki referansın tuttuğu bellek adreside yenisiyle otomatik olarak güncelleştirilecektir. Bundan dolayı ilgili referans her halukarda aynı nesneyi göstermiş olacaktır. Dolayısıyla biz aynı referansla farklı bir bellek bölgesini isteğimiz dışında kullanmış oluyoruz. Haliyle tabiri caizse Garbage Collector mekanizması ile bellek yönetimindeki dönen dolapları ruhumuz duymadığından bu durumları takip etmekle mükellef değiliz.

“Peki Garbage Collector’ın bellek yönetiminde yaptığı yer değiştirmelerden haberdar olmuyorsak bu bizi niye ilgilendiriyor?” sorusunu sorabilirsiniz. Unutmayın… Bellek yönetimini pointerlar ile ele almış bulunuyoruz. Haliyle bu tarz otomatik değişimler manuel yönetim durumlarında beklenmedik bir çok arızaya sebebiyet verebilir. O yüzden cevaplanması gereken soru “Göstericiler kullanırken Garbage Collector’ın bellek yönetiminde yaptığı yer değiştirmeler nasıl sonuçlar doğurabilir?” olacaktır.

Şöyle cevaplayalım. Bir nesnenin üye elemanları üzerinde pointerlarla çalıştığınızı varsayalım. Bu nesnenin Garbage Collector tarafından bellek adresi değiştirildiği an memberlarınında bellek adresleri değiştirilecektir. Haliyle ilgili nesnemizin üye elemanlarını işaretleyen pointerlar boşa çıkmış olacaktır. İşte bu olası durumu engellemek için kullandığımız nesnenin ve üye elemanlarının Garbage Collector tarafından bellek adreslerinin değiştirilmemesi sağlanmalıdır.

fixed anahtar sözcüğü, bir nesnenin üye elemanının bellek adresini sabitlememizi, garbage collector tarafından müdahale edilmemesini sağlamaktadır. Yani ilgili memberı koruma altına aldığımızı düşünebilirsiniz.

Pratik olarak örneklendirmeye geçmeden önce şunu da söylemek isterim ki, zaten fixed keywordünü kullanmadan nesne üyelerinin bellek adreslerini pointer ile tutmak mümkün değildir. Bunun sebebi yukarıda anlattığım olası durumla ilgili olduğu için C# geliştiricileri tarafından bu olası durum baştan engellenmiştir.

Üye elemanlarının adreslerini elde edemediğimiz bu tür nesnelere managed type(yönetilen tip) denilmektedir. Buradan şöyle bir genellemeye varabiliriz ki sınıflar managed type kapsamına girmektedirler.

Şimdi anlattıklarımızı pratik olarak ele alalım.

    class Program
    {
        static void Main(string[] args)
        {
            unsafe
            {
                MyClass myClass = new MyClass();
                int* pointer = &(myClass.MyField);
            }
            Console.Read();
        }
    }
    class MyClass
    {
        public int MyField;
    }

Yukarıdaki kod bloğunu incelerseniz eğer “MyClass” isimli sınıfın “MyField” isminde üye elemanı bulunmaktadır. Bu sınıfın nesnesi üzerinden içerisindeki elemanın bellek adresine erişilmeye çalışıldığı vakit aşağıdaki ekran görüntüsünde olduğu gibi hatayla karşılaşılmaktadır.
C#’ta Gösterici(Pointer) – fixed Anahtar Sözcüğü – VII
Bu hatanın sebebi, biraz önce bahsettiğim gibi nesne elemanlarının bellek adreslerine fixed anahtar sözcüğü olmaksızın erişilmeye çalışılmasıdır. Hatanın asıl nedeni ise yukarıda anlatmaya çalıştığım olası hatanın ta kendisidir.

Bu olası hatayı burada daha somut olarak bir daha ele alırsak eğer; Garbage Collector her an “MyClass” nesnesinin bellek adresini değiştirebilir. Ee buda her an üye eleman olan “MyProperty” değişkenininde bellek adresi değişebilir demek oluyor. Eğer ki bu kullanıma izin verilseydi “MyProperty” bellek adresi ansızın değiştiği durumda “pointer” isimli göstericimiz boşa düşecekti. Daha doğrusu nereye ait olduğu bilinmeyen bir adres taşıyor olacaktı. Ee herhalde bu durumda düşülebilecek olası vahameti gözler önüne getiriyor olsa gerek… Düşünsenize, ne olduğunu bilmediğiniz bir bellek adresi(artık içerisinde işletim sistemini ilgilendiren veriler mi vardır, yoksa başka kritik bir alan mıdır bilemeyiz) üzerinde bilinçli/bilinçsiz farketmeksizin ama yanlış işlemler yaptığımızı…

İşte bu yüzden yukarıdaki kullanım olası hatayı engellemek için yasaklanmıştır ve bir yandanda fixed kullanımı olmadığı için hata vermektedir.

fixed Anahtar Sözcüğünün Kullanımı
fixed keywordünün kullanım prototipi aşağıdaki gibidir.C#’ta Gösterici(Pointer) – fixed Anahtar Sözcüğü – VII

Şimdi yukarılarda yapmaya çalıştığımız örneği fixed keywordü ile tekrarlayalım.

    class Program
    {
        static void Main(string[] args)
        {
            unsafe
            {
                MyClass myClass = new MyClass();
                fixed(int* ipointer = &(myClass.MyField))
                {
                    myClass.MyField = 3;
                    Console.WriteLine($"ipointer : {*ipointer} | MyField : {myClass.MyField}");
                    *ipointer = 13;
                    Console.WriteLine($"ipointer : {*ipointer} | MyField : {myClass.MyField}");
                }
            }
            Console.Read();
        }
    }
    class MyClass
    {
        public int MyField;
    }

Bu şekilde hem aldığımız hata ortadan kalkacaktır, hemde kullandığımız bir nesnenin üye elemanının bellek adresi garbage collector’ın bellek yönetimine karşı korumaya/sabitlenmeye alınacaktır.

Hemen hemen her yapıda olduğu gibi fixed anahtar sözcüğünde de birden fazla kullanım varyasyonu mevcuttur. Mesela birden fazla değişkeni fixed olarak işaretlemek için aşağıdaki prototipte yapıyı kullanabilirsiniz.
C#’ta Gösterici(Pointer) – fixed Anahtar Sözcüğü – VII

    class Program
    {
        static void Main(string[] args)
        {
            unsafe
            {
                MyClass myClass = new MyClass();

                fixed (int* i1 = &myClass.MyField)
                fixed (char* i2 = &myClass.MyField2)
                fixed (bool* i3 = &myClass.MyField3)
                fixed (decimal* i4 = &myClass.MyField4)
                {
                    Console.WriteLine($"MyField : {*i1} | MyField2 : {*i2} | MyField3 : {*i3} | MyField4 : {*i4}");
                }
            }
            Console.Read();
        }
    }
    class MyClass
    {
        public int MyField = 3;
        public char MyField2 = 'a';
        public bool MyField3 = true;
        public decimal MyField4 = 123;
    }

Ayriyetten aşağıdaki varyasyonda da olduğu gibi birden fazla aynı tipteki değişkeni fixed ile işaretleyebiliyoruz.

    class Program
    {
        static void Main(string[] args)
        {
            unsafe
            {
                MyClass myClass = new MyClass();

                fixed (int* pointer1 = &myClass.MyField, pointer2 = &myClass.MyField2)
                {
                    Console.WriteLine($"pointer1 : {*pointer1} | pointer2 : {*pointer2}");
                }
            }
            Console.Read();
        }
    }
    class MyClass
    {
        public int MyField = 3;
        public int MyField2 = 4;
    }

Bu şekilde C# programlama dilinde fixed anahtar sözcüğünün ne işe yaradığından ve varyasyonlarıyla birlikte kullanımından detaylıca bahsetmiş olduk. Bundan sonraki gösterici makale dizisiyle ilgili yazılarımızda yer yer fixed keywordünü kullanacağımızı bildirmek isterim. Ayriyetten bir sonraki yazımızda da göstericilerde dizi işlemlerini ele alacağımızın müjdesini vererek bu içeriğimizi noktalıyorum.

Görüşmek üzere…
İyi çalışmalar…

Bunlar da hoşunuza gidebilir...

5 Cevaplar

  1. Adil dedi ki:

    Əllərinə sağlıq, təşəkkürlər.

  2. Umut dedi ki:

    Çok teşekkürler. Yazınız sayesinde daha iyi anladım.

  1. 22 Mayıs 2017

    […] önceki C#’ta Gösterici(Pointer) – fixed Anahtar Sözcüğü – VII başlıklı makalemizde göstericilerin işaretlediği nesnelerin üye elemanlarının bellek […]

  2. 25 Mayıs 2017

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

Bir cevap yazın

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

*