本文目錄一覽:
- 1、堆棧溢出一般是由什麼原因導致的?
- 2、棧溢出的原因及解決辦法
- 3、python stack overflow 怎麼解決
- 4、Python演算法-爬樓梯與遞歸函數
- 5、python 遞歸限制
- 6、遞歸調用太深,可能導致棧溢出
堆棧溢出一般是由什麼原因導致的?
遞歸過程的局部變數過多、遞歸深度過大,是造成系統棧溢出的原因,特別是遞歸列循環時肯定會發生系統棧溢出。
遞歸堆棧溢出的解決方案是尾部遞歸優化。事實上,尾部遞歸和循環具有相同的效果,所以可以把循環看作是一個特殊的尾部遞歸函數。
尾部遞歸,當函數返回時調用自身,並且返回語句不能包含表達式。通過這種方式,編譯器或解釋器可以優化尾部遞歸,這樣遞歸本身無論被調用多少次,都只佔用一個堆棧幀,而不會出現堆棧溢出。
擴展資料:
針對堆棧溢出可能造成的計算機安全問題,通常有以下這些防範措施:
1、強制代碼遵循正確的規則。
2、使操作系統無法執行緩衝區,從而防止攻擊者植入攻擊代碼。但是,由於攻擊者不必求助於嵌入代碼,而且Linux使用可執行的堆棧屬性來發出信號和在線重用GCC,這種方法仍然有一些弱點。
3、利用編譯器的邊界檢查實現緩衝區保護。這種方法使緩衝區溢出不可能發生,完全消除了緩衝區溢出的威脅,但是代價很高,比如性能較低。
4、對程序指針完整性進行檢查,該方法可以防止絕大多數的緩衝區溢出攻擊。這意味著在程序使用指針之前檢查指針的內容是否已更改。
棧溢出的原因及解決辦法
1,什麼是棧溢出?因為棧一般默認為1-2m,一旦出現死循環或者是大量的遞歸調用,在不斷的壓棧過程中,造成棧容量超過1m而導致溢出。2,解決方案:方法一:用棧把遞歸轉換成非遞歸通常,一個函數在調用另一個函數之前,要作如下的事情:a)將實在參數,返回地址等信息傳遞給被調用函數保存; b)為被調用函數的局部變數分配存儲區;c)將控制轉移到被調函數的入口. 從被調用函數返回調用函數之前,也要做三件事情:a)保存被調函數的計算結果;b)釋放被調函數的數據區;c)依照被調函數保存的返回地址將控制轉移到調用函數.所有的這些,不論是變數還是地址,本質上來說都是”數據”,都是保存在系統所分配的棧中的. 那麼自己就可以寫一個棧來存儲必要的數據,以減少系統負擔。 方法二:使用static對象替代nonstatic局部對象在遞歸函數設計中,可以使用static對象替代nonstatic局部對象(即棧對象),這不僅可以減少每次遞歸調用和返回時產生和釋放nonstatic對象的開銷,而且static對象還可以保存遞歸調用的中間狀態,並且可為各個調用層所訪問。 方法三:增大堆棧大小值當創建一個線程的堆棧時,系統將會保留一個鏈接程序的/STACK開關指明的地址空間區域。但是,當調用CreateThread或_beginthreadex函數時,可以重載原先提交的內存數量。這兩個函數都有一個參數,可以用來重載原先提交給堆棧的地址空間的內存數量。如果設定這個參數為0,那麼系統將使用/STACK開關指明的已提交的堆棧大小值。後面將假定我們使用默認的堆棧大小值,即1MB的保留區域,每次提交一個頁面的內存。 Java在創建線程時設置棧大小:thread(threadgroup group, runnable target, string name, long stacksize)
分配新的 thread 對象,以便將 target 作為其運行對象,將指定的 name 作為其名稱,作為 group 所引用的線程組的一員,並具有指定的堆棧大小
python stack overflow 怎麼解決
stack overflow是堆棧溢出。堆棧溢出的產生是由於過多的函數調用,導致調用堆棧無法容納這些調用的返回地址,一般在遞歸中產生。堆棧溢出很可能由無限遞歸(Infinite recursion)產生,但也可能僅僅是過多的堆棧層級。請對應檢查一下。
Python演算法-爬樓梯與遞歸函數
可以看出來的是,該題可以用斐波那契數列解決。
樓梯一共有n層,每次只能走1層或者2層,而要走到最終的n層。不是從n-1或者就是n-2來的。
F(1) = 1
F(2) = 2
F(n) = F(n-1) + F(n-2) (n=3)
這是遞歸寫法,但是會導致棧溢出。在計算機中,函數的調用是通過棧進行實現的,如果遞歸調用的次數過多,就會導致棧溢出。
針對這種情況就要使用方法二,改成非遞歸函數。
將遞歸進行改寫,實現循環就不會導致棧溢出
python 遞歸限制
python不能無限的遞歸調用下去。並且當輸入的值太大,遞歸次數太多時,python 都會報錯
首先說結論,python解釋器這麼會限制遞歸次數,這麼做為了避免”無限”調用導致的堆棧溢出。
tail recursion 就是指在程序最後一步執行遞歸。這種函數稱為 tail recursion function。舉個例子:
這個函數就是普通的遞歸函數,它在遞歸之後又進行了 乘 的操作。 這種普通遞歸,每一次遞歸調用都會重新推入一個調用堆棧。
把上述調用改成 tail recursion function
tail recursion 的好處是每一次都計算完,將結果傳遞給下一次調用,然後本次調用任務就結束了,不會參與到下一次的遞歸調用。這種情況下,只重複用到了一個堆棧。因此可以優化結構。就算是多次循環,也不會出現棧溢出的情況。這就是 tail recursion optimization 。
c和c++都有這種優化, python沒有,所以限制了調用次數,就是為了防止無限遞歸造成的棧溢出。
如果遞歸次數過多,導致了開頭的報錯,可以使用 sys 包手動設置recursion的limit
手動放大 recursionlimit 限制:
遞歸調用太深,可能導致棧溢出
棧溢出原因:
因為每調用一個方法就會在棧上創建一個棧幀,方法調用結束後就會彈出該棧幀,而棧的大小不是無限的,所以遞歸調用次數過多的話就會導致棧溢出。而遞歸調用的特點是每遞歸一次,就要創建一個新的棧幀,而且還要保留之前的環境(棧幀),直到遇到結束條件。所以遞歸調用一定要明確好結束條件,不要出現死循環,而且要避免棧太深。
解決方法:
當遇到遞歸時,可能出現棧空間不足,出現棧溢出,再申請資源擴大棧空間,如果空間還是不足會出現內存溢出oom。
合理的設置棧空間大小;
寫遞歸方法注意判斷層次;
能用遞歸的地方大多數能改寫成非遞歸方式。
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/182300.html