前幾日,調試一BUG,過程先不說,最後調試到MM,即Debug dcu,然後進入到GetMem.inc中的Get/FreeMem函數處後,出現AV。
然後一通找。。。郁悶了N天,後來發現將MM切換到QMM後,一切正常,然後再切回原MM,BUG出現。。。
按經驗,此類問題一般由於線程未有鎖保護引起,但就是沒找到。
好吧,也不怎麼滴,突然想起IsMultiThread變量,想起MM的Get/Free/Realloc都需要這個玩意進行保護,而VCL中,只有一個地方對這變量進行操作: Classes.TThread.Create->System.BeginThread
然後才想起自己未使用TThread,使用API.CreateThread進行創建線程,而它未對IsMultiThread進行置true操作,問題找到,BUG解除。
遂,本文記錄此問題。
BUG形成:
1:程序未使用TThread或BeginThread進行創建線程,這樣,它就不會對IsMultiThread進行操作
2:自行使用API.Windows.CreateThread創建線程,且未對IsMultiThread置true
3:在創建的線程中,進行Get/Free/ReallocMem,並與其它線程(如主線程)進行交互該內存塊
BUG展現:
1:該BUG將會引起MM數據結構錯誤,問題就大了去。
出現AV時,watch查看的數據是錯誤的,且隨機的給你不一樣的數據
call stack也傻了,定位到無邊際的代碼。。。
總之,一切都傻掉了,不可信了。
BUG避免:
1:慎用API.Windows.CreateThread,如果要對它操作,請記得IsMultiThread := True;
如果不記得,請參照代碼: System.BeginThread
或者直接使用System.BeginThread進行創建線程。
2:使用QMM,QMM是自動維護IsMultiThread,有線程數N(N>1)時, IsMultiThread=true, N=1時, IsMultiThread = false;
這點,其它MM,俺所查看的,都未做處理。(偶在打廣告哩)
個人建議是:開發環境必備兩套以上MM,以作備用,遇到一些莫名問題,切換一下,用以確認是否MM問題引起。
注:
MM=Memory Manager, D2005版本開始集成FastMM。
不過,從D7(D5沒注意看,應該也是)的GetMem.Inc,一直到FastMM4.991都依賴於IsMultiThread標志進行線程保護,未進行自維護該標志。
所以,當出現此BUG條件形成時,就會出現:我知道因為線程保護引起的BUG,但就是找不著在哪裡觸發的,怎麼去解決。
這才是最坑爹的。 :)
完。
2014.10.15 by qsl