Ubuntu Ruby在Rails應用程序中解決內存泄漏問題
在向大家詳細介紹Ubuntu Ruby之前,首先讓大家了解下Ubuntu Ruby,然后全面介紹Ubuntu Ruby,希望對大家有用。
Rails應用程序的內存泄漏問題和解決
內存泄漏是服務器端程序經常遇到的,有時候內存泄漏問題會讓人很頭疼,總體來說,Rails的內存泄漏問題比Java要少得多,這是因為Java內存泄漏最常見的三種情況在Rails當中不存在:
1、HttpSession導致的內存泄漏
Java程序員喜歡往session里面丟很多東西,最糟糕的是竟然有很多框架軟件也肆無忌憚往session里面丟狀態數據,但Rails的session是不放在內存里面的,所以無此煩惱。
2、數據庫連接釋放不徹底
Java的數據庫連接池釋放不徹底,以及查詢游標釋放不徹底,都必然導致內存泄漏。Rails沒有數據庫連接池,而是每個進程持有一個長連接,因此不存在這個問題,而且由于持有長連接,也不存在Java里面的OpenSessionInView的煩惱。
3、用靜態變量持有全局共享數據
Java程序員很喜歡通過靜態全局變量來持有共享數據,但共享數據忘記清理的話,也很容易導致內存泄漏,Ubuntu Ruby是SNA架構,多進程服務器模式,進程間無法共享數據,反而避免了全局共享數據帶來的麻煩。
但是Rails應用有一種情況:在Ubuntu Ruby代碼中調用C寫的第三方Ubuntu Ruby類庫的時候,很容易導致內存泄漏,但這種內存泄漏反而在Java中極其罕見。Ubuntu Ruby本身有GC來管理內存堆,但是代碼一旦調用C寫的第三方Ubuntu Ruby類庫,內存堆的分配權就掌握在第三方C庫的實現上面了,如果這個C庫的代碼質量不夠好,內存泄漏就不可避免。
由于Ubuntu Ruby本身性能很差,因此計算量大的功能往往依賴底層的C庫來實現,這下內存泄漏的潘多拉魔盒就打開了!而Java性能比較好,功能都是純Java編寫,基本上看不到需要依賴第三方C庫的情況,因此比較安全。
JavaEye也面臨著內存泄漏的困擾,這方面困擾主要來自于Rmagic。Rmagick調用ImageMagick的C庫來完成圖片的操作,從我們的監測來看,RMagick大多數情況下會緩慢的泄漏內存,在某些特定的圖片操作上會急劇的泄漏內存。
解決辦法就是用mini_magick替代Rmagick,mini_magick是直接調用ImageMagick的mogrify命令,另起一個進程來操作圖片,操作完進程就結束了,絕無后患,由于Linux的fork進程開銷不大,因此也不必擔心性能問題。
此外,調用第三方C庫的Ubuntu Ruby代碼編寫都需要高度小心,比方說JavaEye使用ferret實現全文檢索,根據應用的需要調用ferret的API來編寫自己的analyzer,其中在實現token_stream方法上面使用了XXXAnalyzer.new和XXXToken.new,XXXFilter.new,
結果內存急劇泄漏,經過檢查發現是Analyzer對象不能被反復創建,改成創建后緩存該對象就好了,但是Filter和Token對象卻必須每次創建,此外ferret的PerAnalyzerFilter也有內存泄漏問題。由于類庫是用C編寫的,單純看API文檔或者看源代碼片斷一般無法判斷出里面的內存泄漏陷阱的。
當遇到了難以解決和定位的內存泄漏問題,Ubuntu Ruby也有類似Java的內存Profiler工具:
1、Memory Profiler
一個純Ubuntu Ruby編寫的內存探測器,原理很簡單,就是用Ubuntu Ruby的對象引用計數器ObjectSpace.each_object去遍歷內存堆中的每個Ubuntu Ruby對象,進行統計和分析。用起來很簡單,非常適合于開發環境下偵測內存泄漏問題,但不能用在生產環境下,極度影響Rails性能。
2、Bleak_house
Bleak_house給Ubuntu Ruby解析器打了補丁,插入相關的指令,可以從底層探測整個Ubuntu Ruby內存堆中對象的情況,然后你可以定期dump出來完整的內存堆里面的所有對象,再用bleak工具去分析dump文件,他比上面的工具分析的信息要全面,可以在測試環境和預發布環境下使用,但在生產環境下,也會對應用的性能產生很大的影響,要慎用。
JavaEye網站在RoR性能方面的經驗就全部分享給大家了,也希望做RoR的朋友都拿出來自己的經驗和大家分享,共同學習和促進RoR的應用和普及。
【編輯推薦】