天天看點

java産生StackOverflowError的原因是什麼?

1、你是不是開來很多線程,然後這些線程還遞歸了?原因應該是棧被你用完了吧。

2、死循環本身是不會StackOverflow的,隻有無限遞歸的時候會出現。原則上循環嵌套次數本身是沒有限制的,限制的是占用的棧空間,如果你的函數裡定義了很多很多變量,棧空間就會用完得比較快。

Java裡面有沒有這種文法不清楚,C#中間可以把struct定義成整個展開的形式,這樣一個struct可能就占很大的空間,而且是unboxing的,放到棧上可能一層就會導緻StackOverflow……

3、 支援 "循環嵌套次數本身是沒有限制的",這個應該是錯的.我看過官方文檔,裡面說是因為嵌套的層次太深導緻的.但是嵌套層次要去到什麼深度才引起java.lang.StackOverflowError,我現在還沒找到.

我的函數嵌套了1k層左右,當初我也以為是棧空間占用太多了導緻的,是以把不必要的變量都去掉,單純的去遞歸,但是還是報StackOverflowError.最後把算法改成不用遞歸,用循環,問題就解決了.

4、遞歸就算什麼變量都不要也是消耗棧空間的,每次調用都要在棧裡面壓一大堆亂七八糟的東西,比如說傳回位址,比如說參數,還可能有執行上下文等等。

5、JVM裡會有兩種StackOverflowError, 一種是對應JVM stack, 一種是對應Native Method stack. 我們一般說的都是JVM stack.

每一個JVM線程維護自己的JVM stack. JVM stack裡面存放 JVM棧幀. 棧幀中存放 資料和中間結果(本地變量數組, 操作符棧, 和對runtime 常量池的引用). 這些資料都比較小(對象都在堆中, 棧幀僅存放對象引用), 是以想單純通過 在棧幀中存放大資料的方法 去引入StackOverflowError, 基本是不現實的.一般都是因為方法調用嵌套層數過大.

http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-2.html#jvms-2.5.2

JVM stack的大小是可以調節的, sun的windows jvm6 x64,jvm棧預設大小為1024k.可以通過-Xss1024k來調節.

http://www.oracle.com/technetwork/java/hotspotfaq-138619.html#threads_oom

做一點實驗:

private int aa=0; private void aaa(){ System.out.println(aa++); aaa(); } @Test public void test3243(){ aaa(); }測試結果: -server -Xss128k 輸出946時溢出java棧 -server -Xss512k 輸出5418時溢出java棧 -server -Xss1280k 輸出14363時溢出java棧 -server -Xss12800k 輸出252223時溢出java棧

6、函數棧溢出 就會出現這個錯誤 一些語言是可以設定遞歸的最大深度的(比如Python) 如果體驗過這個 你就明白這裡的溢出是咋回事了