今天休息,並且也沒有什麼其它事情需要完成,所以就對程式堆疊進行了除錯檢視。
以前一直沒有認真追究過程式的堆疊,只是覺得書上說的就是對的,並不需要驗證,所以對程式堆疊的體會只是停留在書本上的描述。
實驗工具:一台電腦,
vs2008
軟體(其它工具也可以了,只是我機子裝的是這個
ide)
實驗目的:我想知道程式堆疊在記憶體中如何組織,啟動乙個執行緒占用了什麼資源?最多可以啟動多少個執行緒?
實驗過程:
我隨便寫了個程式,在主函式入口處打了斷點,當除錯停下時,轉到彙編**檢視,此時我們觀察
esp的值,會發現這個值大約是乙個
1開始的
16進製制的
6位數,這就說明乙個程式堆疊的起始位址就是
1***xx
這個地方了。
從函式入口處的幾句彙編**可以看出,程式在入口棧的基礎上空出了一片空間,**例如:subesp,100h ,後邊空出多大空間這個數字是變化的,要知道它是幹什麼用的之前,最好先知道它的大小變化時什麼引發的,你如果測試幾個程式就可以發現,它隨著函式中變數的增加而變大,所以這可以充分說明這塊空出來的空間就是為函式內變數存放資料準備的。
子函式的堆疊是怎麼回事?
我們在呼叫乙個子函式時,會將需要的引數壓入堆疊,這個時候子函式就在堆疊當前位置進行與父函式一樣的操作,即空一片空間,給自己函式內的變數使用,函式返回後呼叫者出棧引數資訊。
這樣,我們就有了下乙個問題,子函式可以一直遞迴呼叫下去嗎?記憶體用盡才是盡頭嗎?還是程式堆疊是有限定大小的?
我們隨便寫乙個函式無限遞迴呼叫的測試程式,遞迴函式內宣告乙個
1000
的整型陣列,這樣堆疊生長能夠更快,當然陣列越大生長越快。
程式很快就爆了,當然這和我們預期也是相同的,這個時候我們去檢視堆疊位置時,發現,堆疊位置大約在
0x3***xx
的位置,這說明了什麼呢?說明程式的堆疊不是無限的,也說明了再往後的空間要用作其它用途了,也就是要作為程式堆空間使用。
現在,我們知道了程式堆疊空間的位置,也知道了棧空間的大小,那麼堆空間是剩下的所有空間嗎?
我通過編寫一次分配很大很大的空間,基本上說明了堆就是剩餘的空間。
那麼堆空間裡都有什麼?除了存放全域性資料,動態分配資料,還有其它用途嗎?在思考這個問題前,也許我們該問問自己,程式中啟動多執行緒,執行緒空間在**?
我們可以先理性的思考下,如果執行緒空間類似於函式呼叫方式是否可以,很明顯不可以,因為乙個程式多個執行緒是並行執行的,所以按函式呼叫方式來進行執行緒空間分配必然造成函式呼叫時堆疊混亂的局面,那麼既然不能按函式呼叫方式分配空間,那麼就只能在堆疊空間中分配了,所以我們的執行緒啟動函式一般都有乙個執行緒堆疊空間大小設定的引數,當執行緒中函式也出現了上邊類似函式遞迴呼叫堆疊空間用盡的問題時,程式自然也會爆了,我們也就中獎了,呵呵。
通過這樣的分析,我們自然而然就知道,乙個程式不可能啟動無限多的執行緒,我測試的結果是,乙個程式一般可以啟動
2000
個左右的執行緒。
從上邊的分析,因為動態分配的記憶體,與啟動的執行緒共用所有堆空間,所以,執行緒的多少取決於兩個因素,一是每個執行緒堆疊大小,另乙個是所有執行緒請求的動態記憶體大小,當然,反過來說,動態記憶體申請成功與否也是與執行緒的多少有很多關係的,當乙個程式開了
2000
多個執行緒的時候,這個時候申請記憶體一般都會失敗。這個我也是經過測試確認了的。
通過這次對堆疊測試,讓我感覺充分任務了程式的執行緒之間的關係。
多執行緒的代價
從乙個單執行緒的應用到乙個多執行緒的應用並不僅僅帶來好處,它也會有一些代價。不要僅僅為了使用多執行緒而使用多執行緒。而應該明確在使用多執行緒時能多來的好處比所付出的代價大的時候,才使用多執行緒。如果存在疑問,應該嘗試測量一下應用程式的效能和響應能力,而不只是猜測。雖然有一些多執行緒應用程式比單執行緒...
03多執行緒的代價
從乙個單執行緒的應用到乙個多執行緒的應用並不僅僅帶來好處,它也會有一些代價。不要僅僅為了使用多執行緒而使用多執行緒。而應該明確在使用多執行緒時,能多獲取的好處比所付出的代價大的時候,才使用多執行緒。如果存在疑問,應該嘗試測量一下應用程式的效能和響應能力,而不只是猜測。雖然有一些多執行緒應用程式比單執...
從《迴圈的代價》中學到的
最近在看 演算法競賽入門經典 書中提到迴圈的兩大常見問題,並提出一些建議。第一是算術運算溢位的問題,尤其是n很大而且都是做的乘法的時候。最常見的現象是輸出負值,每步printf也能觀察到。如果換資料型別仍解決不了的話,可能得改演算法了。書中的例子是對最終的取餘 運算作轉化。要計算只包含加法 減法和乘...