Haftalık C++ 59 – Linux C/C++ Uygulamalarında Yığın (“Stack”) Boyutu Ayarlama

Evet sevgili yazılımperver dostlarım, yazımın başlığından da anlaşılacağı üzere, bu yazımda çok spesifik bir konu üzerine eğileceğiz. Daha önceki yazılarımda heap ve stack belleklerinden bahsetmiştim (umarım 🙂 )

Kabaca, uygulama içerisinde, heap, new/malloc ile alınan bellek alanları için kullanılırken, stack ise tanımladığınız yerel değişkenler, iç içe çağırdığımız fonksiyona ilişkin bir takım veriler için kullanılan bellektir (örneğin recursive fonksiyonlarda kontrol hatası yapınca “stack overflow” hatası da aslında buna işaret eder), elbette bundan çok daha fazlası var ama şimdilik bu kadarı yeterli.

Aşağıya internetten bulduğum bir yansıyı da bırakayım. Burada nelerin stack, nelerin ise heap bellek alındığını göstermekte.

Şimdi gelelim problemimize; normalde fonksiyon içerisinde tanımladığımız değişkenler pek büyük olmaz (aslında olmamalı da, statik kod analiz araçları da zaten bunu sizlere söyler) ama bir sebeple buna ihtiyacımız olursa ne yapacağız? İşte bu yazıda, buna cevap arıyor olacağız. Hemen bir örnek ile bakalım:

Bu kodu çalıştırdığınızda “[1] 1979 segmentation fault ./a.out” hatası alabilirsiniz (eğer özellikle stack boyutunu arttırmadıysanız).

Peki ne yapacağız? Öncelikle mevcut stack boyutunu öğrenmeliyiz.

  • Linux işletim sistemleri için “ulimit -s” komutu kullanılabilir,
    • Örneğin benim makinemdeki WSL2’de bu değer 8192
  • Windows uygulamaları için ise Visual Studio içerisindeki /STACK değişkeni ile bunu belirtebiliyorsunuz ve varsayılan değer 1MB
    • Windows için “commit”  ve “reserve” diye iki kavram bulunmaktadır. “Reserve” değeri sanal bellekte stack için ayrılacak alanı ifade ederken, “commit” fiziksel bellekte önden ne kadarlık bir alan ayrılacağını ifade eder. Bu sayede, ihtiyaç olduğunda bu bellek daha hızlı alınabilir.

Bunu öğrendikten sonra artık arttırabiliriz, bunu da:

komutu ile yapabilirsiniz. Bu komutu çağırdıktan sonra yukarıdaki uygulamayı çalıştırmanız durumunda artık hata almadığınızı göreceksiniz. Elbette bu durum, bu shell oturumu üzerinde çalıştırılacak bütün uygulamalar için geçerli olacaktır. Bunu sürekli hale getirmek için bash veya kullandığınız shell ayarlarına ekleyebilirsiniz.

Bu arada, “core dump” konusundan haberdar takipçilerim de bu komutu kullanmış olmaları olasıdır.

Yukarıdaki yöntemin yanında, aşağıdaki gibi bir fonksiyon aracılığı ile de stack boyutunu güncelleyebilirsiniz. Bunu da sistem kaynaklarından ilgili bellek alanını değiştirerek yapıyoruz:

Son ekleme ile nihai kodumuz aşağıdaki gibi olacak. Bu kod ile artık “ulimit -s unlimited” yapmanıza gerek kalmayacak.

Şimdi burada çok ince bir nokta var. İlgili setrlimit fonksiyonunu, main() içerisinde çağırdığım için eğer testFunc() içeriğini buraya alırsanız yine aynı hatayı alıyor olacaksınız. Bunun sebebi ilgili stack boyutunun ayarlandıktan sonraki çağrılar için geçerli olması sebebi ile. Eğer ille main içerisinde kullanma ihtiyacınız var ise ulimit yine bir çözüm olabilir.

İşimiz bitti mi peki? Elbette hayır, kaynaklar kısmına eklediğim setrlimit sayfasına bakarsanız bu çağrının sadece main thread için geçerli olduğunu göreceksiniz. Peki birden fazla thread kullanıyorsak ne yapacağız? İşte burada da, pthread API’lerini kullanıyor olacağız. Çünkü, şu ana kadar (bildiğim/gördüğüm kadarıyla) thread stack boyutunu ayarlayan standart bir yöntem yok, var ise (ulımıt dışında) yorumlar kısmından katkıda bulunabilirsiniz. Aşağıdaki örnekte, ana thread yanında, oluşturulacak diğer thread’ler için izlemeniz gereken yöntemi göstermeye çalıştım:

 

pthread’ler için kullanıma yönelik güzel bir SO sayfasını da kaynaklar kısmına ekliyorum arkadaşlar. Bir sonraki yazımda görüşmek dileğiyle.

Kaynaklar

Bir cevap yazın

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

Bu site, istenmeyenleri azaltmak için Akismet kullanıyor. Yorum verilerinizin nasıl işlendiği hakkında daha fazla bilgi edinin.