2008-09-20 21 views
13

Sau khi nhấn một vài StackOverflowExceptions trong .NET Tôi nhận thấy chúng hoàn toàn bỏ qua các trình xử lý ngoại lệ không được xử lý mà .NET cung cấp (Application.ThreadException/AppDomain.UnhandledException). Điều này rất đáng lo ngại vì chúng tôi có mã dọn dẹp quan trọng trong các trình xử lý ngoại lệ đó.StackOverflowException trong .NET

Có cách nào để khắc phục điều này không?

Trả lời

18

Không thực sự; một tràn ngăn xếp, hoặc một ngoại lệ bộ nhớ xảy ra trong CLR chính nó có nghĩa là một cái gì đó đã đi sai lầm nghiêm trọng (tôi thường nhận được nó khi tôi đã là một dumbass và tạo ra một tài sản đệ quy).

Khi trạng thái này xảy ra, không có cách nào để CLR phân bổ các cuộc gọi hoặc bộ nhớ chức năng mới để cho phép nó gọi vào các trình xử lý ngoại lệ; đó là "chúng tôi phải tạm dừng bây giờ" kịch bản.

Nếu, tuy nhiên, bạn tự ném ngoại lệ cho các trình xử lý ngoại lệ của mình sẽ được gọi.

+0

Tôi thấy có phần đáng ngạc nhiên, sau khi tất cả clr là mã sở hữu của microsoft, họ có thể đã bỏ qua một vài khung ngăn xếp để cho phép xử lý ngoại lệ. – adams

+1

Làm cách nào để biết số tiền cần đặt trước? Trong tình trạng tràn ngăn xếp, chính chồng đã phát triển đến kích thước như vậy mà nó không dễ dàng. Bằng cách đặt trước một số không gian bạn cần phải đặt trước kích thước ngăn xếp tối đa, điều này sẽ lần lượt phân nửa số lượng sẵn có cho phần mềm. – blowdart

+2

Ok, tôi có ý tưởng này ... Loại ... Trong môi trường đơn luồng. Nhưng hey, chúng ta có thể tạo ra nhiều hơn một sợi, phải không? Và mỗi luồng có một ngăn xếp riêng biệt, phải không? Sau đó, tại sao chấm dứt toàn bộ quá trình khi chỉ có một chủ đề chạy ra khỏi ngăn xếp? –

1

Stackoverflow không phải là thứ bạn có thể khôi phục, vì nó không thể cấp phát bộ nhớ ngăn xếp nhiều hơn để gọi bộ xử lý ngoại lệ của bạn.

Điều duy nhất bạn thực sự có thể làm là theo dõi nguyên nhân và ngăn chặn nó xảy ra ở tất cả (ví dụ becareful với đệ quy, và không phân bổ các đối tượng lớn trên ngăn xếp).

25

Có ba loại gọi là "ngoại lệ không đồng bộ". Đó là ThreadAbortException, OutOfMemoryException và StackOverflowException đã đề cập. Những ngoại lệ được phép xảy ra ở bất kỳ hướng dẫn nào trong mã của bạn.

Và, cũng có cách khắc phục chúng:

Dễ nhất là ThreadAbortException. Khi mã hiện tại thực hiện trong một khối cuối cùng. ThreadAbortExceptions là loại "di chuyển" đến cuối của khối cuối cùng. Vì vậy, tất cả mọi thứ trong một khối cuối cùng không thể bị hủy bỏ bởi một ThreadAbortException.

Để tránh ngoại lệ OutOfMemoryException, bạn chỉ có một khả năng: Không phân bổ bất kỳ thứ gì trên Heap. Điều này có nghĩa là bạn không được phép tạo bất kỳ loại tham chiếu mới nào.

Để khắc phục StackOverflowException, bạn cần một số trợ giúp từ Framework. Sự trợ giúp này thể hiện trong các Vùng Thực thi Hạn chế. Ngăn xếp cần thiết được phân bổ trước khi mã thực tế được thực hiện và bổ sung cũng đảm bảo rằng mã đã được JIT biên dịch và có sẵn để thực thi.

Có ba hình thức để thực thi mã trong vùng Execution Constrained (sao chép từ BCL Team Blog):

  • ExecuteCodeWithGuaranteedCleanup, một hình thức ngăn xếp tràn an toàn của một thử/cuối cùng.
  • Một khối thử/cuối cùng được đặt trước ngay lập tức bằng một cuộc gọi tới RuntimeHelpers.PrepareConstrainedRegions. Khối thử không bị ràng buộc, nhưng tất cả các khối bắt, cuối cùng và lỗi đều được thử.
  • Là trình hoàn thiện quan trọng - bất kỳ lớp con nào của CriticalFinalizerObject đều có trình kết thúc được chuẩn bị háo hức trước khi một thể hiện của đối tượng được cấp phát.
    • Trường hợp đặc biệt là phương pháp ReleaseHandle của ReleaseHandle, một phương pháp ảo được chuẩn bị háo hức trước khi phân lớp được phân bổ và được gọi từ trình xác nhận quan trọng của SafeHandle.

Bạn có thể tìm thêm ở những bài đăng trên blog:

Constrained Execution Regions and other errata [Brian Grunkemeyer] tại BCL Team Blog.

Weblog của Joe Duffy về Atomicity and asynchronous exception failures nơi ông đưa ra tổng quan rất tốt về ngoại lệ không đồng bộ và tính chắc chắn trong khung .net.

+0

Lưu ý rằng không phải tất cả không gian ngăn xếp cần thiết nếu được phân bổ trước, chỉ có khoảng 12 trang (48K hoặc 96K). Nếu mã quan trọng cần nhiều không gian hơn thì nó sẽ thất bại và CER sẽ không giúp được gì. CER chỉ tăng một chút bảo đảm thực hiện, nó không đảm bảo 100%. – Pragmateek

1

blowdart đóng đinh nó ở trên. Dumbass đệ quy tài sản, như ông thích gọi nó. Thực sự chỉ là vấn đề với việc nhập mã quá nhanh.

private Thing _myThing = null; 

Public Thing MyThing 
{ 
    get{ 
     return this.MyThing;} 
    set{ 
     this.MyThing = value;} 
} 
+0

Bạn không trả lời câu hỏi gốc .. – nawfal

Các vấn đề liên quan