C # bir yığın taşması istisnasını yakala


116

Yığın taşması özel durumu oluşturan bir yönteme yinelemeli çağrım var. İlk çağrı bir try catch bloğu ile çevrilidir ancak istisna yakalanmaz.

Yığın taşma istisnası özel bir şekilde mi davranır? İstisnayı doğru bir şekilde yakalayabilir / ele alabilir miyim?

Alakalı olup olmadığından emin değilim, ancak ek bilgiler:

  • istisna ana iş parçacığına atılmaz

  • kodun istisnayı attığı nesne Assembly.LoadFrom (...) tarafından manuel olarak yüklenir. CreateInstance (...)


3
@RichardOD, hatayı düzelttim çünkü bir hataydı. Bununla birlikte, sorun farklı bir şekilde görünebilir ve bunu halletmek istiyorum
Toto

7
Kabul edildiğinde, yığın taşması, yakalanmaması gereken ciddi bir hatadır . Bunun yerine bozuk kodu düzeltin.
Ian Kemp

11
@RichardOD: Bir kimse, örneğin özyinelemeli bir ayrıştırıcı tasarlamak istiyorsa ve ana makinenin gerektirdiği derinliğin ötesinde yapay sınırlar koymak istemiyorsa, bu konuda nasıl hareket edilmelidir? Eğer uyuşturuculara sahip olsaydım, açıkça yakalanabilecek bir StackCritical istisnası olurdu ve hala küçük bir yığın alanı kalmışken ateşlenirdi; atılana kadar kendini etkisiz hale getirir ve güvenli miktarda yığın alanı kalana kadar yakalanamaz.
supercat

3
Bu soru kullanışlıdır - bir yığın taşması istisnası meydana gelirse bir birim testinde başarısız olmak istiyorum - ancak NUnit, testi diğer istisnalarda olduğu gibi başarısız olmak yerine "yok sayıldı" kategorisine taşır - onu yakalamam gerekiyor ve Assert.Failonun yerine yapın. Cidden - bunu nasıl yapacağız?
BrainSlugs83

Yanıtlar:


109

2.0'dan başlayarak bir StackOverflow İstisnası yalnızca aşağıdaki durumlarda yakalanabilir.

  1. CLR, ana bilgisayarın özellikle StackOverflow istisnalarının işlenmesine izin verdiği, barındırılan bir ortamda * çalıştırılmaktadır.
  2. Stackoverflow istisnası, gerçek bir yığın taşması durumu nedeniyle değil, kullanıcı kodu tarafından atılır ( Referans )

* "Kodum CLR'yi barındırıyor ve CLR seçeneklerini yapılandırıyorum" gibi "barındırılan ortam", "kodum paylaşılan barındırmada çalışıyor" değil


29
İlgili herhangi bir scebario'da yakalanamıyorsa, StackoverflowException nesnesi neden var?
Manu

9
@Manu en az birkaç nedenden dolayı. 1) 1.1'de yakalanabilir miydi ve dolayısıyla bir amacı vardı. 2) CLR'yi barındırıyorsanız hala yakalanabilir, bu nedenle hala geçerli bir istisna türüdür
JaredPar

3
Yakalanamıyorsa ... Neyin olduğunu açıklayan windows olayı neden varsayılan olarak tam yığın izlemeyi içermiyor?

11
StackOverflowExceptions'ın barındırılan bir ortamda ele alınmasına nasıl izin verilir? Sormamın nedeni, barındırılan bir ortam çalıştırmam ve uygulama havuzunun tamamını yok ettiği yerde tam olarak bu sorunu yaşıyorum. En üste geri dönebileceği iş parçacığını iptal etmeyi tercih ederim ve daha sonra hatayı günlüğe kaydedebilir ve tüm uygulama havuzunun iş parçacığı öldürülmeden devam edebilirim.
Brain2000

Starting with 2.0 ...Merak ediyorum, SO yakalamalarını engelleyen nedir ve bu nasıl mümkün olmuştur 1.1(yorumunuzda bundan bahsetmiştiniz)?
M.kazem Akhgary

47

Doğru yol, taşmayı düzeltmektir, ama ...

Kendinize daha büyük bir yığın verebilirsiniz: -

using System.Threading;
Thread T = new Thread(threadDelegate, stackSizeInBytes);
T.Start();

Kullandığınız kareleri saymak ve bir çerçeve sınırına ulaşıldığında kendi özel durumunuzu atmak için System.Diagnostics.StackTrace FrameCount özelliğini kullanabilirsiniz.

Ya da kalan yığının boyutunu hesaplayabilir ve bir eşiğin altına düştüğünde kendi istisnanızı atabilirsiniz: -

class Program
{
    static int n;
    static int topOfStack;
    const int stackSize = 1000000; // Default?

    // The func is 76 bytes, but we need space to unwind the exception.
    const int spaceRequired = 18*1024; 

    unsafe static void Main(string[] args)
    {
        int var;
        topOfStack = (int)&var;

        n=0;
        recurse();
    }

    unsafe static void recurse()
    {
        int remaining;
        remaining = stackSize - (topOfStack - (int)&remaining);
        if (remaining < spaceRequired)
            throw new Exception("Cheese");
        n++;
        recurse();
    }
}

Sadece Peyniri yakala. ;)


47
Cheesespesifik olmaktan uzaktır. Ben giderimthrow new CheeseException("Gouda");
C. Evhuis

13
@ C.Evenhuis Gouda o ( "Double Gloucester") gerçekten görmek bir RollingCheeseException olmalıdır istisnai peynir olduğuna hiç şüphe yok iken cheese-rolling.co.uk

3
lol, 1) düzeltmek mümkün değildir çünkü onu yakalamadan genellikle nerede olduğunu bilmiyorsunuz 2) Stacksize'ı arttırmak sonsuz özyineleme ile işe yaramaz ve m 3) Yığın doğru yerde kontrol edilmesi ilk gibi
Firo

2
ama ben laktoza tahammülsüzüm
redoc

39

StackOverflowException s üzerindeki MSDN sayfasından :

.NET Framework'ün önceki sürümlerinde, uygulamanız bir StackOverflowException nesnesini yakalayabilir (örneğin, sınırsız özyinelemeden kurtarmak için). Ancak, bir yığın taşması istisnasını güvenilir bir şekilde yakalamak ve program yürütmeye devam etmek için önemli miktarda ek kod gerektiğinden, bu uygulama şu anda tavsiye edilmemektedir.

.NET Framework sürüm 2.0'dan başlayarak, bir StackOverflowException nesnesi bir dene-yakala bloğu tarafından yakalanamaz ve karşılık gelen işlem varsayılan olarak sonlandırılır. Sonuç olarak, kullanıcılara yığın taşmasını algılamak ve önlemek için kodlarını yazmaları önerilir. Örneğin, uygulamanız özyinelemeye bağlıysa, özyinelemeli döngüyü sonlandırmak için bir sayaç veya durum koşulu kullanın. Ortak dil çalışma zamanını (CLR) barındıran bir uygulamanın, CLR'nin yığın taşması istisnasının meydana geldiği uygulama etki alanını kaldırmasını ve karşılık gelen işlemin devam etmesine izin vermesini belirtebileceğini unutmayın. Daha fazla bilgi için, bkz. ICLRPolicyManager Arabirimi ve Ortak Dil Çalışma Zamanını Barındırma.


23

Birkaç kullanıcının daha önce söylediği gibi, istisnayı yakalayamazsınız. Bununla birlikte, nerede olduğunu bulmakta zorlanıyorsanız, görsel stüdyoyu atıldığında kırılacak şekilde yapılandırmak isteyebilirsiniz.

Bunu yapmak için, 'Hata Ayıkla' menüsünden İstisna Ayarları'nı açmanız gerekir. Visual Studio'nun eski sürümlerinde, bu 'Hata Ayıklama' - 'İstisnalar'; daha yeni sürümlerde, "Hata Ayıkla" - "Windows" - "İstisna Ayarları" konumundadır.

Ayarları açtıktan sonra, 'Ortak Dil Çalışma Zamanı İstisnaları'nı genişletin,' Sistem'i genişletin, aşağı kaydırın ve 'System.StackOverflowException' öğesini işaretleyin. Ardından çağrı yığınına bakabilir ve yinelenen çağrı modelini arayabilirsiniz. Bu size yığının taşmasına neden olan kodu düzeltmek için nereye bakmanız gerektiği konusunda bir fikir vermelidir.


1
Nerede Hata Ayıklama - VS 2015'teki İstisnalar?
FrenkyB

1
Hata Ayıklama - Windows - İstisna Ayarları
Simon

15

Yukarıda birkaç kez bahsedildiği gibi, bozuk işlem durumu nedeniyle Sistem tarafından oluşturulan bir StackOverflowException'ı yakalamak mümkün değildir. Ancak istisnayı bir olay olarak fark etmenin bir yolu var:

http://msdn.microsoft.com/en-us/library/system.appdomain.unhandledexception.aspx

.NET Framework sürüm 4'ten başlayarak, olay işleyicisi güvenlik açısından kritik olmadığı ve HandleProcessCorruptedStateExceptionsAttribute özniteliğine sahip olmadığı sürece, işlemin durumunu (yığın taşmaları veya erişim ihlalleri gibi) bozan istisnalar için bu olay başlatılmaz.

Bununla birlikte, uygulamanız olay işlevinden çıktıktan sonra sona erecektir (ÇOK kirli bir çözüm, uygulamayı bu olay içinde yeniden başlatmaktı haha, bunu yapmadım ve asla yapmayacak). Ama giriş yapmak için yeterince iyi!

.NET Framework 1.0 ve 1.1 sürümlerinde, ana uygulama iş parçacığı dışındaki bir iş parçacığında oluşan işlenmemiş bir istisna, çalışma zamanı tarafından yakalanır ve bu nedenle uygulamanın sonlandırılmasına neden olmaz. Bu nedenle, uygulama sonlandırılmadan UnhandledException olayının ortaya çıkması mümkündür. NET Framework sürüm 2.0'dan başlayarak, alt iş parçacıklarındaki işlenmemiş istisnalar için bu geri döndürmez durdurucu kaldırıldı, çünkü bu tür sessiz hataların kümülatif etkisi, performans düşüşünü, bozuk verileri ve kilitlenmeleri içeriyordu ve bunların tümü hata ayıklaması zordu. Çalışma zamanının sona ermediği servis taleplerinin listesi dahil olmak üzere daha fazla bilgi için, Yönetilen İş Parçacıklarındaki İstisnalar konusuna bakın.


6

Evet, CLR 2.0'dan itibaren yığın taşması kurtarılamaz bir durum olarak kabul edilir. Böylece çalışma zamanı hala süreci kapatır.

Ayrıntılar için lütfen http://msdn.microsoft.com/en-us/library/system.stackoverflowexception.aspx belgelerine bakın.


CLR 2.0'dan StackOverflowException, işlemi varsayılan olarak sona erdirir.
Brian Rasmussen

Hayır. OOM'yi yakalayabilirsiniz ve bazı durumlarda bunu yapmak mantıklı olabilir. İplik kaybolmakla ne demek istediğini anlamıyorum. Bir iş parçacığının işlenmemiş bir istisnası varsa, CLR işlemi sonlandıracaktır. İpliğiniz yöntemini tamamlarsa temizlenecektir.
Brian Rasmussen

5

Yapamazsın. CLR size izin vermeyecek. Yığın taşması önemli bir hatadır ve kurtarılamaz.


Öyleyse, yakalanabilir olmak yerine birim test çalıştırıcısını çökertirse, bu istisna için bir Birim Testinin başarısız olmasını nasıl sağlarsınız?
BrainSlugs83

1
@ BrainSlugs83. Yapmıyorsun, çünkü bu aptalca bir fikir. Kodunuz yine de bir StackOverflowException ile başarısız olursa neden test ediyorsunuz? CLR, daha derin bir yığını işleyebilmek için değişirse ne olur? Halihazırda derinlemesine iç içe geçmiş bir yığın bulunan bir yerde birim test işlevinizi çağırırsanız ne olur? Test edilemeyen bir şey gibi görünüyor. Manuel olarak atmaya çalışıyorsanız, görev için daha iyi bir istisna seçin.
Matthew Scharley

5

Gönderilerin çoğunun açıkladığı gibi yapamazsınız, başka bir alan eklememe izin verin:

Birçok web sitesinde, bundan kaçınmanın yolunun farklı bir AppDomain kullanmak olduğunu söyleyen insanlar bulacaksınız, bu durumda bu durumda alan kaldırılacaktır. Bu kesinlikle yanlıştır (CLR'nizi barındırmadığınız sürece), çünkü CLR'nin varsayılan davranışı bir KillProcess olayı oluşturarak varsayılan AppDomain'inizi düşürür.


3

Bu imkansız ve iyi bir nedenden ötürü (birincisi, etraftaki tüm bu yakalamaları (İstisna) {} düşünün).

Yığın taşmasından sonra yürütmeye devam etmek istiyorsanız, tehlikeli kodu farklı bir AppDomain'de çalıştırın. CLR politikaları, orijinal alanı etkilemeden taşma durumunda mevcut AppDomain'i sonlandıracak şekilde ayarlanabilir.


2
"Catch" ifadeleri gerçekten bir sorun olmazdı, çünkü bir catch ifadesi çalıştırıldığında, sistem iki yığın alanı kullanmaya çalışmış olanın etkilerini geri alırdı. Yığın taşması istisnalarını yakalamanın tehlikeli olması için hiçbir neden yok. Bu tür istisnaların yakalanamamasının nedeni, güvenli bir şekilde yakalanmalarına izin vermenin , yığılmasa bile yığını kullanan tüm koda fazladan ek yük eklemeyi gerektirmesidir .
supercat

4
Bir noktada ifade iyi düşünülmüyor. Stackoverflow'u yakalayamazsanız, bunun bir üretim ortamında NEREDE olduğunu asla bilemezsiniz.
Offler
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.