2009-10-17 32 views
6

Nếu không sử dụng đệ quy thì có thể ném ngoại lệ tràn ngăn xếp như thế nào?Nếu không sử dụng đệ quy thì có thể ném ngoại lệ tràn ngăn xếp như thế nào?

+0

Xin lỗi vì sự thân câu hỏi lặp đi lặp lại, nhưng tôi không thể nghĩ về bất cứ điều gì trong khi giá trị thêm. – JaredCacurak

+0

Không sao. Tôi thường thấy mình trong cùng một suituation :) – pierrotlefou

+0

Bạn luôn có thể đặt nt (không có văn bản) trong cơ thể. Điều đó luôn làm việc trong những ngày BBS. –

Trả lời

12

Nếu bạn gọi đủ phương pháp, tràn ngăn xếp có thể xảy ra bất cứ lúc nào. Mặc dù, nếu bạn gặp lỗi tràn ngăn xếp mà không sử dụng đệ quy, bạn có thể muốn suy nghĩ lại cách bạn đang làm việc. Nó rất dễ dàng với đệ quy bởi vì trong một vòng lặp vô hạn, bạn gọi một tấn phương pháp.

16

Khai báo mảng ENORMOUS dưới dạng biến cục bộ.

+0

Hầu hết các trình biên dịch sẽ không biên dịch được. Đó không phải là tràn ngăn xếp. –

+1

@Chris - Sẽ không biên dịch nó? Tôi nghĩ rằng kích thước stack tối đa đã được thiết lập bởi trình liên kết, và không được biết đến trình biên dịch. – ChrisW

+2

trình biên dịch không thể bắt được nó, trừ khi trình biên dịch có khả năng phân tích mã cho việc sử dụng thời gian chạy dự kiến, có thể cực kỳ phức tạp. – JustJeff

2

Mọi cuộc gọi phương thức chưa trả lại đều tiêu thụ một số không gian ngăn xếp. (Các phương thức có nhiều biến cục bộ hơn tiêu thụ nhiều không gian hơn.) Ngăn xếp cuộc gọi rất sâu có thể dẫn đến tràn ngăn xếp.

Lưu ý rằng trên các hệ thống có bộ nhớ hạn chế (thiết bị di động và như vậy), bạn không có nhiều không gian ngăn xếp và sẽ sớm hết.

+1

Tôi đã làm việc trên một dự án bàn điều khiển nơi các quy trình của chúng tôi có các ngăn xếp 32K. Trong một trong những thói quen, có hai mảng 16K. Mặc dù việc sử dụng các mảng là độc quyền và chúng không nằm trong cùng phạm vi, trình biên dịch vẫn phân bổ 32K không gian ngăn xếp và tràn ngăn xếp của chúng ta (về mặt lý thuyết một trình biên dịch thông minh hơn sẽ chỉ được đặt trước 16K). Tôi đã thay đổi cả hai để phân bổ/miễn phí để khắc phục sự cố. – Adisak

20

Vì không có ai khác đã đề cập đến nó:

throw new System.StackOverflowException(); 

Bạn có thể làm điều này khi kiểm tra hoặc làm lỗi tiêm.

+1

Tuyệt vời - giả sử bạn đang sử dụng .NET =) –

1

Nếu bạn đang nói về C++ với thư viện tiêu chuẩn hợp lý, tôi hình ảnh rằng điều này sẽ làm việc:

while (true) { 
    alloca(1024 * 1024); // arbitrary - 1M per iteration. 
} 

Chi tiết về alloca.

+0

Đó có phải là một luồng ngăn xếp hoặc hết bộ nhớ ngoại lệ không? – Juliet

+2

@juliet: Hàm alloca() phân bổ không gian trong khung ngăn xếp của người gọi. – pierrotlefou

+2

Điều này không nên ném ngoại lệ nếu alloca() được triển khai đúng cách. Cuộc gọi alloca() là nghĩa vụ phải trả về NULL nếu không có đủ không gian ngăn xếp thay vì ném một ngoại lệ. Điều gì sẽ xảy ra là sau khi bạn chạy ra khỏi không gian ngăn xếp, mã của bạn sẽ bị mắc kẹt trong một vòng lặp vô hạn của alloca() gọi trả về NULL. – Adisak

2

Câu trả lời ngắn gọn: nếu bạn có đối tượng gọi là đối tượng bên trong, bạn tăng dấu vết ngăn xếp lên 1. Vì vậy, nếu bạn có 1000 đối tượng lồng vào nhau, mỗi đối tượng gọi đối tượng bên trong, cuối cùng bạn sẽ nhận được tràn ngăn xếp.

Dưới đây là một cuộc biểu tình như thế nào để tạo ra số nguyên tố sử dụng vòng lặp lồng nhau:

using System; 
using System.Collections.Generic; 
using System.Text; 

namespace ConsoleApplication1 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      Program p = new Program(); 

      IEnumerator<int> primes = p.AllPrimes().GetEnumerator(); 
      int numberOfPrimes = 1000; 
      for (int i = 0; i <= numberOfPrimes; i++) 
      { 
       primes.MoveNext(); 
       if (i % 1000 == 0) 
       { 
        Console.WriteLine(primes.Current); 
       } 
      } 
      Console.ReadKey(true); 
     } 

     IEnumerable<int> FilterDivisors(IEnumerator<int> seq, int num) 
     { 
      while (true) 
      { 
       int current = seq.Current; 
       if (current % num != 0) 
       { 
        yield return current; 
       } 
       seq.MoveNext(); 
      } 
     } 

     IEnumerable<int> AllIntegers() 
     { 
      int i = 2; 
      while (true) 
      { 
       yield return i++; 
      } 
     } 

     IEnumerable<int> AllPrimes() 
     { 
      IEnumerator<int> nums = AllIntegers().GetEnumerator(); 
      while (true) 
      { 
       nums.MoveNext(); 
       int prime = nums.Current; 
       yield return prime; 

       // nested iterator makes a big boom  
       nums = FilterDivisors(nums, prime).GetEnumerator(); 
      } 
     } 
    } 
} 

Không có đệ quy, nhưng chương trình sẽ ném một ngoại lệ stack overflow sau khoảng 150.000 số nguyên tố.

+0

ncie code, nhắc tôi về Evolution của lập trình viên Haskell :) (tấn mã chống oneliner - lập trình giai thừa) –

7

Những điều sau đây áp dụng cho Windows, nhưng hầu hết các hệ điều hành đều thực hiện điều này theo cách tương tự.

Câu trả lời ngắn gọn là: nếu bạn chạm vào trang bảo vệ cuối cùng, trang sẽ bị ném.

Ngoại lệ loại EXCEPTION_STACK_OVERFLOW (C00000FD) được nâng lên khi ứng dụng của bạn chạm vào trang dưới cùng của ngăn xếp, được đánh dấu là cờ bảo vệ PAGE_GUARD và không có chỗ để tăng ngăn xếp (cam kết thêm một trang), xem How to trap stack overflow in a Visual C++ application.
Trường hợp điển hình khi điều này xảy ra là khi chồng đã phát triển như là kết quả của nhiều khung chức năng trên ngăn xếp (ví dụ, ngoài kiểm soát đệ quy), do ít khung hơn nhưng kích thước khung hình rất lớn (các chức năng có kích thước rất lớn) đối tượng phạm vi cục bộ) hoặc bằng cách phân bổ rõ ràng từ ngăn xếp với _alloca.
Một cách khác để gây ra ngoại lệ là chỉ cố ý chạm vào trang bảo vệ, ví dụ: bằng cách dereferencing một con trỏ trỏ vào trang đó. Điều này có thể xảy ra do lỗi khởi tạo biến.

Ngăn xếp ngăn xếp có thể xảy ra trên đường dẫn thực thi hợp lệ nếu đầu vào gây ra mức lồng nhau rất sâu.Ví dụ thấy Stack overflow occurs when you run a query that contains a large number of arguments inside an IN or a NOT IN clause in SQL Server.

-1

Cách dễ nhất để thực hiện một StackOverflowException được như sau:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

namespace ConsoleApplication2 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      SomeClass instance = new SomeClass(); 
      string name = instance.Name; 
     } 
    } 

    public class SomeClass 
    { 
     public string Name 
     { 
      get 
      { 
       return Name; 
      } 
     } 
    } 
} 
+1

Thực ra đây là cách dễ dàng thứ 2 sau khi chỉ ném ngoại lệ :) –

+3

Câu hỏi được loại trừ cụ thể đệ quy. – meriton

+0

Bạn đúng, sai lầm của tôi. –

0
int main() 
{ 
    //something on the stack 
    int foo = 0; 
    for (
    //pointer to an address on the stack 
    int* p = &foo; 
    //forever 
    ; 
    //ever lower on the stack (assuming that the stack grows downwards) 
    --p) 
    { 
    //write to the stack 
    *p = 42; 
    } 
} 
Các vấn đề liên quan