2011-01-19 34 views
78

Tôi cần phải đi sâu bao nhiêu trong ngăn xếp cuộc gọi trước khi nhận được StackOverflowError? Câu trả lời có phụ thuộc vào nền tảng không?Độ sâu tối đa của ngăn xếp cuộc gọi java là gì?

+1

Liên quan chặt chẽ: http://stackoverflow.com/questions/794227/how-to-know-about-outofmemory-or-stackoverflow-errors-ahead-of-time – finnw

+0

Vì đây là một câu hỏi hay, tôi đã cập nhật tiêu đề cho một cái gì đó tôi cảm thấy rõ ràng hơn liên quan đến ý nghĩa. (Trước đây tôi nghĩ bạn có thể đề cập đến chiều sâu của một ngăn xếp * cụ thể * mà bạn đã nắm bắt trong thời gian chạy, ví dụ). Vui lòng thay đổi lại nếu bạn không đồng ý. –

+0

@Andrzej - không phản đối. – ripper234

Trả lời

48

Nó phụ thuộc vào lượng bộ nhớ ảo được cấp phát cho ngăn xếp.

http://www.odi.ch/weblog/posting.php?posting=411

Bạn có thể điều chỉnh này với tham số -Xss VM hoặc với các nhà xây dựng Thread(ThreadGroup, Runnable, String, long).

+12

Và có lẽ kích thước của các khung ngăn xếp bạn đang đặt trên đó? – duffymo

+1

Giới hạn cũng phụ thuộc vào mức sử dụng ngăn xếp trong chức năng. –

+0

nếu chúng ta không đề cập đến Xss thì sao? –

19

Kích thước ngăn xếp có thể được đặt bằng công tắc dòng lệnh -Xss nhưng theo quy tắc chung, nó đủ sâu, hàng trăm nếu không phải hàng nghìn cuộc gọi sâu. (Mặc định là nền tảng phụ thuộc, nhưng ít nhất 256k ở hầu hết các nền tảng.)

Nếu bạn gặp lỗi tràn, 99% thời gian do lỗi trong mã.

+3

+1 cho đoạn thứ hai. Người ta phải luôn luôn nhớ về điều đó. – mcveat

+6

Sử dụng nhật thực, tôi chỉ nhận được 1024 cuộc gọi đệ quy. – Norswap

+0

@Norswap Bạn có xác định được kích thước của dấu vết ngăn xếp không? Điều đó dường như bị giới hạn ở 1024 bất kể kích thước thực của ngăn xếp. –

21

Tôi đã thử nghiệm trên hệ thống của mình và không tìm thấy bất kỳ giá trị không đổi nào, đôi khi ngăn xếp tràn xảy ra sau 8900 cuộc gọi, đôi khi chỉ sau 7700, số ngẫu nhiên.

public class MainClass { 

    private static long depth=0L; 

    public static void main(String[] args){ 
     deep(); 
    } 

    private static void deep(){ 
     System.err.println(++depth); 
     deep(); 
    } 

} 
+7

Đó không phải là trường hợp đó là đuôi đệ quy và không bao giờ nên tràn? Chỉnh sửa: Xin lỗi. Trong Java nó bị rơi ở 8027; ở Scala nó lên đến 8594755 trước khi tôi chán. – arya

+6

@arya một phần quan trọng của ngữ nghĩa JVM là việc đệ quy đuôi không được hỗ trợ. Điều này mang lại rất nhiều vấn đề thú vị cho những ai muốn thực hiện ngôn ngữ với đệ quy đuôi trên JVM. –

+1

'public foo() {try {foo(); } cuối cùng {foo(); }} ' có thể chạy 'hầu như' mãi mãi, chỉ trong java. – Felype

2

Hãy so sánh hai cuộc gọi sau đây:
(1) phương pháp tĩnh:

public static void main(String[] args) { 
    int i = 14400; 
    while(true){ 
     int myResult = testRecursion(i); 
     System.out.println(myResult); 
     i++; 
    } 
} 

public static int testRecursion(int number) { 
    if (number == 1) { 
     return 1; 
    } else { 
     int result = 1 + testRecursion(number - 1); 
     return result; 
    }  
} 
//Exception in thread "main" java.lang.StackOverflowError after 62844 

(2) phương pháp không tĩnh nhờ sủ dụng một lớp học khác nhau:

public static void main(String[] args) { 
    int i = 14400; 
    while(true){  
     TestRecursion tr = new TestRecursion(); 
     int myResult = tr.testRecursion(i); 
     System.out.println(myResult); 
     i++; 
    } 
} 
//Exception in thread "main" java.lang.StackOverflowError after 14002 

Kiểm tra lớp đệ quy có public int testRecursion(int number) { làm phương pháp duy nhất.

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