Bu yazıda kod yazarken belki intellisense pencereseninde adını görüp merak ettiğiniz belki de arada kullandığınız stackalloc
ifadelerinden bahsedeceğiz. stackalloc
ifadesi en basit anlatımla stack üzerinde belirtilen kadar bir blok memory allocate etmek için kullanılır. Stack üzerinde allocate edilen bu alan metot sonlanmasıyla beraber otomatik olarak boşa çıkacağı için GC üzerinde de herhangi bir yük oluşturmamakta. Özellikle ufak arraylerle çalıştığımız senaryolarda stackalloc tercih etmek GC üzerindeki yükü hafifletecektir.
C# 7.2 öncesinde stackalloc ifadelerini kullanmak istediğimizde unsafe kod yazmamız gerekiyordu. Bu da özellikle bu ifadenin daha geniş kapsamlı kullanımını limitlemekteydi. Ancak C# 7.2 ile beraber stackalloc ifadesiyle allocate ettiğimiz alana Span
stackalloc ifadesiyle yarattığımız alanı doğrudan Span veya ReadOnlySpan'e aşağıdaki gibi assign edebiliriz.
Span<int> span = stackalloc int[10];
Stackalloc ile bir alan yaratılırken array initializers ile ilk değer ataması da yapabiliyoruz.
Span<int> span = stackalloc int[5] { 1, 2, 3, 4, 5 };
Stack üzerinde alan allocate etmek ve bu memory alanına erişmek daha hızlı olsa da tabi ki bazı limitleri bulunmakta. Stack üzerinde çok fazla alan kullanımı StackOverflowException
hatalarına sebep olabilir. Burada yapılacak en doğru kullanım stack üzerinde yaratılan alan boyutunu limitlemek. Eğer size gereken alan limitlediğiniz alandan fazlaysa gereken alanı heap üzerinde yaratmak. Hem heap üzerinde hem de stack üzerinde yarattığımız alanlara erişimi Span<T> ve ReadOnlySpan<T>
kullanarak yapabildiğimiz için yazdığımız kod üzerinde de değişiklik yapmamız gerekmemekte.
const int MaxStackLimit = 1024; Span<byte> buffer = inputLength <= MaxStackLimit ? stackalloc byte[inputLength] : new byte[inputLength];
stackalloc kullanımında yapılan hatalardan biri de döngü içerisinde sürekli olarak stackalloc ile memory allocate etmek. Döngü sayısının arttığı durumlarda bu şekilde bir kullanım yine StackOverflowExceptiona sebep olabilmekte. Bunun yerine ilgili memory alanını döngüye girmeden allocate edip döngü içerisinde bu alanı yeniden kullanmak en optimize ve doğru kullanım.
StackOverflowException almaya müsait kullanım
for (int i = 0; i < length; i++) { Span<int> array = stackalloc int[length]; }
Daha optimize kullanım
Span<int> array = stackalloc int[length]; for (int i = 0; i < length; i++) { }
stackalloc yerine göre kullanıldığında heap üzerinde allocationa neden olmadan hızlı bir şekilde ilgili stack alanını kullanıp metot bitiminde boşa çıkarabilmemizi sağlayan kuvvetli bir araç. Ancak doğru yerde kullanmak ve doğru şekilde kullanmak oldukça önemli. Doğru şekilde kullanılmadığı durumlarda istenmeyen sonuçlarla karşılaşmamız oldukça olası. Örneğin, .NET Runtime içerisinde stackalloc kullanımında 1K byte limiti bulunmakta. Eğer ihtiyacınız olan 1K byte'tan büyükse bu alanı heap üzerinde yaratmanız tavsiye ediliyor. Bu gibi tavsiyelere uyulmadığı veya gözden kaçırıldığı durumda sorunlarla karşılaşmanız çok olası. Örnek durumlardan birine buradan ulaşabilirsiniz.
Bir sonraki yazıda görüşmek üzere,