寫出本文僅僅是處於備忘的目的。
最近為現在做的軟體新增了乙個記憶體**機制(以前處於某種記憶體只申請不釋放,這並不等於記憶體洩露,因為我們知道這些記憶體塊在記憶體中的位置)-- 在某一塊記憶體不使用的時候將其釋放掉,以防止記憶體緩慢增長。
由於以前沒有釋放記憶體,所以就不存在野指標的問題。於是乎肯定坑爹的事情就從記憶體釋放開始了 。。。 /大哭
只從新增了記憶體釋放機制之後軟體就出現了各種崩潰 。。。
好了,閒話少說,直奔主題。
乙個記憶體塊很多地方引用,一旦乙個地方釋放記憶體,而且其他地方還在引用,那後果就 。。。
1.
當時我就想這個問題很簡單啊,典型的野指標問題嘛 。。。
於是就給記憶體塊的指標加了個引用計數(引用一次引用計數就加一次(原子操作)),釋放記憶體塊時並不是真的釋放而是把引用計數減一(原子操作),當引用計數減到0時才會把記憶體給釋放掉 。。。
說道這個各位看客一定以為這個問題就圓滿解決了 。 其實 。。。 坑爹的事還沒完 才 真正的剛剛開始 。。。 /大哭/大哭/大哭
加了引用計數之後,程式穩定比以前好多了,但是基本上每個1個小時就會崩潰一次 。。。
於是開始各種查詢問題 。。。
後來發現問題還是出在資源釋放的問題上,請看如下**:
int release()interlockeddecrement的確是原子操作,但是後面的語句卻不是,當多執行緒存在的時候可能 interlockedderement 會被執行兩次 之後 第乙個 的if 語句才會執行(如果想不明白就好好想,哈哈),這樣的問題就是會導致 改記憶體塊被釋放兩次 。。。else
return(m_nrefcount);
}
2.
吃一塹長一智 。。。 後來**改成了這個樣子
hresult release()這樣呼叫interlockedderement之後得到的引用計數就不會受影響了 。。。 至少不會重複delete 自己吧 。。。else
return(m_nrefcount);
}
3.
這樣修改之後軟體的確更加穩定啦,執行5-6個小時沒問題 。。。 但是 。。。 5-6個小時之後 ,軟體依然崩潰,依然崩潰,依然崩潰 。。。
為什麼呢?當時也是各種想不通 。。。 後來經過苦思冥想和各種極端除錯手段終於發現了問題:
請看我增加引用的方法:
ulong addref( void )原來我對記憶體的引用並不是先引用而後釋放,而是 引用和釋放穿插使用的,由於是多執行緒,同時增加引用和資源釋放並不是互斥執行的,有可能會同時執行,同時執行,同時執行 。。。
當同時執行的時候就會有極小的概率導致引用計數減為0,到delete語句被執行的間隙,存在一次引用計數加一的動作 ,這樣記憶體塊看似沒有被釋放(引用計數為1)其實已經釋放了,這樣就產生了野指標,產生了野指標,產生了野指標!!!
找到了問題,卻不好解決 。。。 因為不能再release和addref裡面新增鎖,因為使用它的地方太多了,影響效率不說 還可能會導致死鎖。
後來只能在可能會出現這種狀況的地方新增鎖,還好能夠產生這種狀況的地方不多。
後來問題圓滿解決 。。。
C 記憶體洩露 與 野指標總結
跟前輩交流收穫心德,使用非常精煉的形式描述記憶體洩露與野指標的本質。在此與大家分享,歡迎多多交流。下面給出理解描述 指標變數作用域 被指向物件生命週期 造成的結果 情況一 超出作用域 生命週期未結束 記憶體洩露 情況二 在作用域內 生命週期結束 野指標 情況三 超出作用域 生命週期結束 正確的執行 ...
記憶體洩露與野指標的思考
資料大小與指標大小?int a sizeof char a的值為1.int b sizeof char b的值隨編譯器和作業系統改變。在win32系統,應該是4.32位定址 即4byte。不應妄自揣度記憶體大小 struct mystruct long takes 4byte int takes 2...
C語言記憶體(野指標 )
1.堆 在鍊錶中找接近4位元組的空間,發現 5位元組接近 4位元組,將 5位元組給程式。2.靜態儲存區 編譯時就存在 儲存全域性變數和靜態區域性變數 3.野指標 1 區域性指標變數沒有初始化 struct student char name int number int main struct st...