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