设置线程堆栈大小_哇擦,传说中的堆栈溢出和快速排序
stack overflow
堆棧溢出和快速排序這兩個概念對開發人員來說并不陌生,但是通知都只是聽說過,真正開發過程中卻很少會遇到。我也是敲代碼好些行后非常有幸撞上了,而且還是兩個一起出現的,這其中過程的滋味還是相當酸爽,值得回味。問題背景:
某項目中有個POI離線檢索功能,比如搜索附近的加油站,底層引擎邏輯提供了一個C函數。
輸入:經緯點,搜索范圍半徑,搜索類別。
輸出:按照距離由近到遠排好序的POI結果列表。
這是一個C函數,是同步接口,所以我在OC 上層做了一次封裝,改成了異步調用,在子線程中執行。問題現象:
(1)如果搜索加油站,酒店等匹配結果數據較少的類型,功能正常;
(2)如果搜索飯店,酒店這種匹配結果較多的類型時,則會導致程序Crash。Crash時線程堆棧顯示crash在搜索子線程,Crash對應的代碼行不固定,每次crash時都不一樣,略詭異,但是都是Crash在對搜索結果進行快速排序的那個快排函數中;
(3)如果我減少搜索范圍的半徑,再搜索飯店或者酒店時,功能又正常了。問題分析:
(1)只有檢索結果列表中元素比較多的時候才出現問題,元素較少時功能正常;
(2)快速排序函數是非常標準的實現,而且大多數類別的搜索都是正常的,所以應該可以排除嫌疑。但是Crash線程調用堆棧卻顯示掛在了快速排序函數里面。說明函數的執行環境有問題;
快速排序函數代碼
(3)該函數是放在子線程中執行的。難道是子線程默認堆棧空間太小,快速排序遞歸層級過多時因為堆棧溢出導致crash? 特意查了一些蘋果官方文檔,
apple堆棧大小說明
iOS系統中子線程默認堆棧大小是512K,果然比較小。問題解決方案:
(1)直接增大子線程的堆棧大小。我用的是Cocoa的線程NSThread,直接通過setStackSize方法配置線程堆棧大小,需要注意的是配置的stacksize最小值是16k,而且必須是4K的整數倍。需要在線程開始執行之前進行配置(NSThread 對象的start方法調用之前)。
調整堆棧大小
(2)對快速排序做優化。問題總結:1、關于堆棧溢出
一般情況下應用程序是不需要考慮堆和棧的大小的,但是事實上堆和棧都不是無上限的,過多的遞歸會導致棧溢出,過多的alloc變量會導致堆溢出。默認情況下iOS主線程1M,子線程512K。
iOS 應用程序執行時內存布局如下圖所示:
內存空間
在應用程序分配的內存空間里面,最低地址位是固定的代碼段和數據段,往上是堆,向上生長,用來存放全局變量,對于 ObjC對象 來說,就是 alloc 出來的變量,都會放進這里,堆不夠用的時候就會往上申請空間。最頂部高地址位是棧,向下生長,局部的基本類型變量都會放進棧里,函數調用時參數、返回地址等信息都是放在棧里。 ObjC 的對象都是以指針進行操控的,局部變量的指針都在棧里,全局的變量的指針在堆里。所以預防堆棧溢出的方法:
(1)避免層次過深的遞歸調用;
(2)不要使用過多的局部變量,控制局部變量的大小;
(3)避免分配占用空間太大的對象,并及時釋放;
(4)實在不行,適當的情景下調用系統API修改線程的堆棧大小;2、關于快速排序的優化
快速排序是數據結構課程中介紹的最基礎的一種算法。這里單獨拿出來聊這個話題,主要是想強調兩個事情,第一,基礎真的很重要;第二,基礎算法在實際編程中確實可能用到不多,大部分情況下都是直接調用系統的封裝好的接口即可,但并不代表不會遇到,并且校招面試中出現幾率也是比較大的。
關于快速排序的優化,百度里面一搜能找到很多方法,甚至還有不少人用這個題目來寫各種小論文。我這里也簡單分享一下我覺得比較容易實現且效果較好的方法。
我們先看看快速排序的標準教科書實現:
快速排序標準實現改進措施如下:
(1)中樞值的選取。這個很顯然,如果每次都選中實際大小中中間的那個值,那么就能達到最優的排序效果,避免最壞的情況的;
(2)劃分的最小數列長度。因為快速排序是對子序列不停遞歸的一個過程(分治法)。所以如果遞歸的過多,堆棧帶來的性能損失也是不容小視的。還有最重要的一點就是在數據量很小的情況下,插入排序在時間上的性能要比快速排序的性能要好,所以當子序列長度小于某閾值時,調整為插入排序;
(3)對是否交換做標記,如果全過程沒有發生交換,直接返回就可以了;
(4)棧的深度。要優先對小的數組進行排序,這樣可以減少遞歸調用棧的深度。
改進后的偽代碼如下:
快速排序改進
快速排序改進
當然,用非遞歸的方式來實現快速排序或者去掉尾遞歸也是另外一種思路的優化,感興趣的同學可以去嘗試一下。
微信公眾號:云峰小羅,分享 編程.生活.段子
總結
以上是生活随笔為你收集整理的设置线程堆栈大小_哇擦,传说中的堆栈溢出和快速排序的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python简单图画程序_用Python
- 下一篇: python中setpos_如何用类初始