Java中的StackOverflowError錯誤問題及解決方法_第1頁
Java中的StackOverflowError錯誤問題及解決方法_第2頁
Java中的StackOverflowError錯誤問題及解決方法_第3頁
Java中的StackOverflowError錯誤問題及解決方法_第4頁
Java中的StackOverflowError錯誤問題及解決方法_第5頁
已閱讀5頁,還剩4頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

第Java中的StackOverflowError錯誤問題及解決方法目錄StackOverflowError簡介StackFrames和StackOverflowerError的發(fā)生方式StackOverflowerError正在運(yùn)行解決StackOverflowError結(jié)論

StackOverflowError簡介

StackOverflowError可能會讓Java開發(fā)人員感到惱火,因?yàn)樗俏覀兛赡苡龅降淖畛R姷倪\(yùn)行時錯誤之一。在本文中,我們將通過查看各種代碼示例以及如何處理它來了解此錯誤是如何發(fā)生的。StackFrames和StackOverflowerError的發(fā)生方式讓我們從基礎(chǔ)開始。調(diào)用方法時,將在調(diào)用堆棧上創(chuàng)建新的堆棧幀(stackframe)。該堆??蚣馨徽{(diào)用方法的參數(shù)、其局部變。

StackOverflowError可能會讓Java開發(fā)人員感到惱火,因?yàn)樗俏覀兛赡苡龅降淖畛R姷倪\(yùn)行時錯誤之一。

在本文中,我們將通過查看各種代碼示例以及如何處理它來了解此錯誤是如何發(fā)生的。

StackFrames和StackOverflowerError的發(fā)生方式

讓我們從基礎(chǔ)開始。調(diào)用方法時,將在調(diào)用堆棧上創(chuàng)建新的堆棧幀(stackframe)。該堆??蚣馨徽{(diào)用方法的參數(shù)、其局部變量和方法的返回地址,即在被調(diào)用方法返回后應(yīng)繼續(xù)執(zhí)行方法的點(diǎn)。

堆棧幀的創(chuàng)建將繼續(xù),直到到達(dá)嵌套方法中的方法調(diào)用結(jié)束。

在此過程中,如果JVM遇到?jīng)]有空間創(chuàng)建新堆棧幀的情況,它將拋出StackOverflower錯誤。

JVM遇到這種情況的最常見原因是未終止/無限遞歸StackOverflowerr的Javadoc描述提到,錯誤是由于特定代碼段中的遞歸太深而引發(fā)的。

然而,遞歸并不是導(dǎo)致此錯誤的唯一原因。在應(yīng)用程序不斷從方法內(nèi)調(diào)用方法直到堆棧耗盡的情況下,也可能發(fā)生這種情況。這是一種罕見的情況,因?yàn)闆]有開發(fā)人員會故意遵循糟糕的編碼實(shí)踐。另一個罕見的原因是方法中有大量局部變量。

當(dāng)應(yīng)用程序設(shè)計(jì)為類之間具有循環(huán)關(guān)系時,也可以拋出StackOverflowError。在這種情況下,會重復(fù)調(diào)用彼此的構(gòu)造函數(shù),從而引發(fā)此錯誤。這也可以被視為遞歸的一種形式。

另一個引起此錯誤的有趣場景是,如果一個類在同一個類中作為該類的實(shí)例變量實(shí)例化。這將導(dǎo)致一次又一次(遞歸)調(diào)用同一類的構(gòu)造函數(shù),最終導(dǎo)致堆棧溢出錯誤。

StackOverflowerError正在運(yùn)行

在下面所示的示例中,由于意外遞歸,開發(fā)人員忘記為遞歸行為指定終止條件,將拋出StackOverflowError錯誤:

publicclassUnintendedInfiniteRecursion{

publicintcalculateFactorial(intnumber){

returnnumber*calculateFactorial(number-1);

}

在這里,對于傳遞到方法中的任何值,在任何情況下都會引發(fā)錯誤:

publicclassUnintendedInfiniteRecursionManualTest{

@Test(expected=ahref="/tag/stackoverflowerror"rel="externalnofollow"rel="externalnofollow"title="查看更多關(guān)于StackOverflowError的文章"target="_blank"StackOverflowError/a.class)

publicvoidgivenPositiveIntNoOne_whenCalFact_thenThrowsException(){

intnumToCalcFactorial=1;

UnintendedInfiniteRecursionuir

=newUnintendedInfiniteRecursion();

uir.calculateFactorial(numToCalcFactorial);

@Test(expected=StackOverflowError.class)

publicvoidgivenPositiveIntGtOne_whenCalcFact_thenThrowsException(){

intnumToCalcFactorial=2;

UnintendedInfiniteRecursionuir

=newUnintendedInfiniteRecursion();

uir.calculateFactorial(numToCalcFactorial);

@Test(expected=StackOverflowError.class)

publicvoidgivenNegativeInt_whenCalcFact_thenThrowsException(){

intnumToCalcFactorial=-1;

UnintendedInfiniteRecursionuir

=newUnintendedInfiniteRecursion();

uir.calculateFactorial(numToCalcFactorial);

}

但是,在下一個示例中,指定了終止條件,但如果將值-1傳遞給calculateFactorial()方法,則永遠(yuǎn)不會滿足終止條件,這會導(dǎo)致未終止/無限遞歸:

publicclassInfiniteRecursionWithTerminationCondition{

publicintcalculateFactorial(intnumber){

returnnumber==11:number*calculateFactorial(number-1);

}

這組測試演示了此場景:

publicclassInfiniteRecursionWithTerminationConditionManualTest{

@Test

publicvoidgivenPositiveIntNoOne_whenCalcFact_thenCorrectlyCalc(){

intnumToCalcFactorial=1;

InfiniteRecursionWithTerminationConditionirtc

=newInfiniteRecursionWithTerminationCondition();

assertEquals(1,irtc.calculateFactorial(numToCalcFactorial));

@Test

publicvoidgivenPositiveIntGtOne_whenCalcFact_thenCorrectlyCalc(){

intnumToCalcFactorial=5;

InfiniteRecursionWithTerminationConditionirtc

=newInfiniteRecursionWithTerminationCondition();

assertEquals(120,irtc.calculateFactorial(numToCalcFactorial));

@Test(expected=StackOverflowError.class)

publicvoidgivenNegativeInt_whenCalcFact_thenThrowsException(){

intnumToCalcFactorial=-1;

InfiniteRecursionWithTerminationConditionirtc

=newInfiniteRecursionWithTerminationCondition();

irtc.calculateFactorial(numToCalcFactorial);

}

在這種特殊情況下,如果將終止條件簡單地表示為:

publicclassRecursionWithCorrectTerminationCondition{

publicintcalculateFactorial(intnumber){

returnnumber=11:number*calculateFactorial(number-1);

}

下面的測試在實(shí)踐中顯示了這種情況:

publicclassRecursionWithCorrectTerminationConditionManualTest{

@Test

publicvoidgivenNegativeInt_whenCalcFact_thenCorrectlyCalc(){

intnumToCalcFactorial=-1;

RecursionWithCorrectTerminationConditionrctc

=newRecursionWithCorrectTerminationCondition();

assertEquals(1,rctc.calculateFactorial(numToCalcFactorial));

}

現(xiàn)在讓我們來看一個場景,其中StackOverflowError錯誤是由于類之間的循環(huán)關(guān)系而發(fā)生的。讓我們考慮ClassOne和ClassTwo,它們在其構(gòu)造函數(shù)中相互實(shí)例化,從而產(chǎn)生循環(huán)關(guān)系:

publicclassClassOne{

privateintoneValue;

privateClassTwoclsTwoInstance=null;

publicClassOne(){

oneValue=0;

clsTwoInstance=newClassTwo();

publicClassOne(intoneValue,ClassTwoclsTwoInstance){

this.oneValue=oneValue;

this.clsTwoInstance=clsTwoInstance;

}

publicclassClassTwo{

privateinttwoValue;

privateClassOneclsOneInstance=null;

publicClassTwo(){

twoValue=10;

clsOneInstance=newClassOne();

publicClassTwo(inttwoValue,ClassOneclsOneInstance){

this.twoValue=twoValue;

this.clsOneInstance=clsOneInstance;

}

現(xiàn)在讓我們假設(shè)我們嘗試實(shí)例化ClassOne,如本測試中所示:

publicclassCyclicDependancyManualTest{

@Test(expected=StackOverflowError.class)

publicvoidwhenInstanciatingClassOne_thenThrowsException(){

ClassOneobj=newClassOne();

}

這最終導(dǎo)致了StackOverflowError錯誤,因?yàn)镃lassOne的構(gòu)造函數(shù)實(shí)例化了ClassTwo,而ClassTwo的構(gòu)造函數(shù)再次實(shí)例化了ClassOne。這種情況反復(fù)發(fā)生,直到它溢出堆棧。

接下來,我們將看看當(dāng)一個類作為該類的實(shí)例變量在同一個類中實(shí)例化時會發(fā)生什么。

如下一個示例所示,AccountHolder將自身實(shí)例化為實(shí)例變量JointaCountHolder:

publicclassAccountHolder{

privateStringfirstName;

privateStringlastName;

AccountHolderjointAccountHolder=newAccountHolder();

}

當(dāng)AccountHolder類實(shí)例化時,由于構(gòu)造函數(shù)的遞歸調(diào)用,會引發(fā)StackOverflowError錯誤,如本測試中所示:

publicclassAccountHolderManualTest{

@Test(expected=StackOverflowError.class)

publicvoidwhenInstanciatingAccountHolder_thenThrowsException(){

AccountHolderholder=newAccountHolder();

}

解決StackOverflowError

當(dāng)遇到StackOverflowError堆棧溢出錯誤時,最好的做法是仔細(xì)檢查堆棧跟蹤,以識別行號的重復(fù)模式。這將使我們能夠定位具有問題遞歸的代碼。

讓我們研究一下由我們前面看到的代碼示例引起的幾個堆棧跟蹤。

如果忽略預(yù)期的異常聲明,則此堆棧跟蹤由InfiniteCursionWithTerminationConditionManualTest生成:

java.lang.StackOverflowError

atc.b.s.InfiniteRecursionWithTerminationCondition

.calculateFactorial(InfiniteRecursionWithTerminationCondition.java:5)

atc.b.s.InfiniteRecursionWithTerminationCondition

.calculateFactorial(InfiniteRecursionWithTerminationCondition.java:5)

atc.b.s.InfiniteRecursionWithTerminationCondition

.calculateFactorial(InfiniteRecursionWithTerminationCondition.java:5)

atc.b.s.InfiniteRecursionWithTerminationCondition

.calculateFactorial(InfiniteRecursionWithTerminationCondition.java:5)

在這里,可以看到第5行重復(fù)

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論