一開始主線程a是作為乙個對話方塊ctestdlg存在,現在,在ctestdlg的成員函式onstartthread中開始乙個新執行緒b,onstartthread函式中cstring區域性變數stra(注1)作為執行緒b工作函式的引數pparam,ctestdlg的成員函式onendthread用於設定中止執行緒b,見下面的示例**1:
... 執行緒a(主線程)
ctestdlg::onstartthread()
void cmsitestdlg::onendthread()
... 執行緒b
uint threadproc(lpvoid pparam)
sleep(200); // 模擬線程工作
}return 0; //正常返回0
}在這裡,執行緒a與執行緒b的執行是非同步的,即執行緒a無需等待執行緒b的完成,啟動執行緒b後,先進入執行緒b的工作函式:
struct cstringdata};
// cleanup ole if required
if (pthread->m_lpfnoletermorfreelib != null)
(*pthread->m_lpfnoletermorfreelib)(true, false);
if (bdelete)
pthread->delete();
pstate->m_pcurrentwinthread = null;}
// allow cleanup of any thread local objects
afxtermthread();
// allow c-runtime to cleanup, and exit the thread
_endthreadex(nexitcode);
#endif //!_mt
}afxendthread通過呼叫pthread->delete()會使執行緒b的棧清空(開始執行緒b時就已為執行緒b分配了棧:參考3),然後將執行緒b工作函式中已為所有變數分配的棧全部清空,包括strb,但是這不會使strb得以正常析構,也就無法將堆資料的引用計數減1,並最終不會釋放堆資料,引發了記憶體洩漏!
針對此,我另做了乙個測試,並證明了strb確實未被正常析構,見下面的示例**2:
... 執行緒a(主線程)
ctestdlg::onstartthread()
void cmsitestdlg::onendthread()
... 執行緒b
uint threadproc(lpvoid pparam)
g_bstopthread = true; //只進入一次, 下一次就終止自已
sleep(200); // 模擬線程工作
}return 0; //正常返回0
}比之示例1**,加了兩行**(粗體顯示)。
g_bstopthread = true,使執行緒b立刻在下一次迴圈時結束;
waitforsingleobject(m_pthread->m_hthread, infinite),等待
至於為什麼執行緒自我終止不能使執行緒內部物件正常析構,我需要進一步查閱相關資料,以後將會彌補。
2003.11.9 14:21
我同意某位仁兄的看法,堆就是堆,棧就是棧。
國內很多寫書或譯書的把堆(heap)寫成堆疊,把棧(stack)也寫成堆疊。事實上兩者是不同的。
樓主寫的是棧(stack).棧就是執行緒一開始作業系統分配給這個執行緒的一塊記憶體(樓主已經講的很詳細了)。當你某個函式的區域性變數很大比如接近1m,棧(stack)就會溢位。
堆正如mayax所說的那樣,分預設堆和輔助堆,在c++,c中使用delete,new,malloc、free 來操作預設堆(預設大小為1mb)。堆是不會溢位的。只有分配失敗。比如 pvoid pv = malloc(0x100000);當malloc看到預設堆中沒有這麼大的記憶體就會返回null,這就是分配失敗。當然預設堆不夠用了的話,在 win32中你可以用heapcreate來建立乙個輔助堆,用heapalloc來分配堆記憶體,用heapfree來釋放堆記憶體,用 heapdestroy來銷毀這個輔助堆。
建議對這個東西還弄不懂的多看看jeffrey richter的《windows核心程式設計》,這裡面把win32的記憶體管理講的很清楚,不過這本書的中譯者還是把stack翻譯成堆疊,把heap也翻譯成堆疊。
另外值得一提的是全域性變數不是放在堆裡面而是放在pe檔案的資料節(section),當作業系統裝載程式的時候把pe檔案的資料節對映到**,全域性變數就在那塊記憶體裡面。這個大家可以了解一下pe結構。
多執行緒全域性物件析構導致執行緒執行出錯
這樣的問題應該大多出現在大的程式裡面,出現這樣問題一般具備幾個條件 1 全域性物件太多 2 多執行緒 3 執行緒很多,主程序沒有等待執行緒結束 4 主程序由於某種原因終止 原因分析 首先全域性物件太多,主程序結束時需要一定的時間析構各全域性物件 此時,先析構的全域性物件由於主程序忙著析構其他的全域性...
面試題之使用無界佇列的執行緒池會導致記憶體飆公升嗎?
答案 會 分析 建立執行緒池方式有如下幾種 executors.newfixedthreadpool 10 linkedblockingqueue 無限加入佇列 executors.newscheduledthreadpool 10 delayedworkqueue 佇列如果滿了,阻塞 execut...
面試題之使用無界佇列的執行緒池會導致記憶體飆公升嗎?
答案 會 分析 建立執行緒池方式有如下幾種 executors.newfixedthreadpool 10 linkedblockingqueue 無限加入佇列 executors.newscheduledthreadpool 10 delayedworkqueue 佇列如果滿了,阻塞 execut...