GC與Memory pool引發的一段血案

來源:互聯網
上載者:User

今天坐我旁邊的兩個同事討論了一個由記憶體管理引發的BUG,涉及到了Memery management中一些令人頭疼的東東,值得說一下。
情況是這樣的:我們的代碼裡面自己實現了一個native C++的memory pool來對某些類別的對象進行管理,而這個pool不是thread safe的。這樣設計也很容易理解,一來實現一個thread safe的pool要頗費一番心血,在當時的情況下沒有必要;二來,我想也是更重要的,thread safe裡面大量的lock(不管選擇何種同步機制)必然導致performence的嚴重損失,作為像memory management這樣的底層工具,效能是至關重要的考慮因素。這個pool幾年來一直都運行得很好,不過隨著MS的.NET的引入,產品中用到了一些C++/CLI的manage code,其中很多的managed object都對native heap object進行了一對一的映射,native object的life cycle由managed object控制,簡單的說就是在其constructor當中建立,finalizer當中釋放(實際情況當然比這個複雜,不過不妨礙這裡的討論)。而managed object的life cycle是由GC管理的。眾所周知,CLR的GC自己運行在一個獨立的thread當中(要是真能這樣與世無爭多好啊,一聲歎息...)。好,問題來了,如果一個本機物件現在被託管對象映射到,然而這個本機物件在內部又是由記憶體池管理,會發生什嗎???
因為GC運行在一個獨立的線程裡面,它會根據系統狀況判斷何時進行垃圾收集,當然一般情況下這些對我們來說都是transparent的。然而如果碰巧在記憶體池進行某些操作的時候GC啟動了垃圾收集,一種競爭的情況就產生了(這個世界競爭還真是無處不在,想到以前做電路模擬時候大部分經曆就是花在了這兩個字上,SIGH~~)。比如記憶體池拿到了一個對象,但是在操作之前碰巧GC回收了一個託管對象,導致這個本機物件release掉,如果這個時候pool繼續操作前面拿到的對象指標......結果當然就是application有了crush的機會。當然,實際中這樣的可能性其實並不大,據同事說是在連續建立了10萬個託管對象,逼GC造反之後才reproduce了這個bug的(大家都不容易呀,呵呵)。不過畢竟這種可能性是存在的,還是要想辦法fix掉。
要從根本機制上解決這個問題並不容易。畢竟已經涉及到了最底層的memory management的東西,如果真要動pool的話那可是牽一髮而動全身的大事,就不是一個bug的問題了。後來,有人提出能否在可能產生pool操作的幾段code裡面強制讓GC先對託管對象進行回收,進而引發本機物件的釋放,然後再讓pool繼續進行操作。這個思路貌似是可以解決我們這個BUG的。最後,我提議他們使用GC::Collect() + GC::WaitForPendingFinalizers()來進行同步...問題據說解決了,當然這也只能算一個應急的方法。
其實單就這個BUG而言,解決問題的方法遠遠不如分析的過程來得精彩,這也是我寫本文的原因。 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.