<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    放翁(文初)的一畝三分地

      BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
      210 隨筆 :: 1 文章 :: 320 評論 :: 0 Trackbacks
    越是忙,雜七雜八的事情越多,最近正在優化Memcache的客戶端代碼,這時候SIP突然出現OOM的問題(Out of Memory),作開發最頭痛就是這種問題,壓力測試都作過,早期的幾個版本都沒有出現這樣的問題,因此懷疑可能是最近一次發布修改引起的。借助JProfiler在測試環境搭了一套系統,開始做壓力測試,來分析Memory到底流到了哪里去了。

    問題一:連接池泄漏

           看到這個問題,我想很多人都說,都什么年代了,使用開源的現成連接池,怎么還會有這樣的問題,又不是那些使用jdbc的年代了。那來看看現象吧。

    場景:測試部用loadRunner往死里壓,發現很多業務對象不斷增長,但是按照業務場景來說,這些業務對象處理以后就自動釋放了。(在本地的開發環境驗證了是會自動釋放的)

    JProfiler截圖:

           上圖中可以看到有很多業務對象已經累積占用了不少內存,在讓測試部同學停掉壓力測試以后,等待了一會兒,然后用JProfiler主動發起垃圾回收,也看到了Jboss后臺有GC回收的記錄輸出以后,發現這些對象依然存在,也就是說這些對象成為了Memory泄漏的誘因之一。但是就如我所說的,在本地測試以及白盒測試來看,這些對象在一次請求以后,處理完畢一定會被釋放,沒有被其他MapReference,然后通過JProfiler看了看這些對象的Allocation Call Tree,就是我們處理請求的Servlet作為源頭的,但為什么Servlet沒有被清理掉呢?接著來看看后面二張圖

           既然知道對象存在并且被Hold了,那么就去看看線程運行的狀況,這一看發現有很多線程都處于Wait的狀態(其實在serverdump也可以看到),這張圖上就可以看到,我選擇了其中一個wait的線程它處于等待狀態的原因就是在ibatisThrottleincrement的時候處于等待狀態,看了看ibatis的代碼,這部分代碼其實是ibatis連接池的一段代碼,在連接池被占滿以后,處于等待釋放的狀態,也就是說程序把連接池耗盡了。

           為了驗證是否是耗盡了,讓DBA老大光輝給我看了看MySql(這部分當天的日志數據都保存在MySql中)的連接情況,發現只有8個連接,看來不是真的耗盡,應該是連接池泄露了。光輝告訴我,這八個連接都在做同一個查詢,就是統計某一個API的訪問記錄次數和流量。在當前的業務流程中對于MySql主要做了兩類操作:

           1.訪問控制計數器創建的統計查詢。

    由于要對Open API訪問控制,采用了Memcache計數器方式來實現。當發現此類API沒有創建過計數器,那么就分析MySql中的數據,創建計數器,后續的訪問記錄除了插入數據庫以外還需要累加計數器,這樣訪問控制可以高效使用集中式計數器而不需要查詢數據庫。

    2.日志批量異步寫入。

    對于Open API的記錄采用了線程池中每一個線程維護一個內存分頁,當頁滿或者到了刷新間隔時,一次性批量寫入數據庫,緩解數據庫寫入壓力,這里采用了事務來批量提交。

           對于第一種操作,由于設計中MySql就只會保留當天的數據量,因此只有系統啟動的時候做一次統計,對于數據庫壓力和Sql執行來說應該沒有太大的壓力,但是由于壓力測試是從昨天下午就開始做的,里面的數據已經有上千萬,因此這次重新啟動開始做壓力測試,導致了這個創建計數器的Sql執行很慢。同時日志的批量寫入采用的是事務方式來提交,對于MySql其實自己還不是很深入,但是感覺上來說,問題應該出現在這里,由于查詢的緩慢在加上事務批量的提交,可能會造成事務失敗,同時沒有正確的將釋放資源的信號傳遞給ibatis,導致了看起來的連接資源耗盡。

           我將數據庫中的記錄全部刪除,然后重新啟動,開始壓力測試,問題不存在了,對象都及時得到回收。后續還會去跟進這個問題,在ibatis早期版本,同樣是這個類出現了死鎖的問題,后來升級得到了解決,但是也看到很多國外的朋友說道2.22.3其實還是有死鎖的問題,不過我個人覺得可能還是和數據庫也有一定關系。

    疑問:

           這個問題的背后我還有一點疑問,對于我們來說,如果一個普通的http請求,當超時以后肯定就會自動中斷,但是在這個場景中,我足足等了1個小時還是沒有釋放,也就是說客戶端其實已經斷開了,但是JBoss好像并不會釋放這些處理請求的事務,導致資源被卡。

    問題二:LinkedBlockingQueue惹禍

           自從Jdk1.5以后concurrent包為大家提供了很多便利高效的開發新模式,我在不少地方用到了LinkedBlockingQueue,作為消費者和生產者之間的數據通道,消費者們等待在LinkedBlockingQueue門口守候生產者提供數據,獲取數據后就開始并行處理。這里我會采用queue.poll(100,TimeUnit.MILLISECONDS)這種方式來半阻塞的獲取數據。其實在昨天已經聽說LinkedBlockingQueue可能存在著內存泄露的問題,看了看很多網上的人也都提到了這個問題,在1.5種沒有得到解決,在1.6中會去fix這個問題,但是沒有證據,也不好亂加斷定。在問題一搞好以后,然后繼續查找潛在bug,這時候不經意的發現有一個對象隨著時間的推移始終在增加,但是由于單個對象占的內存不大,因此沒有很明顯的體現出來,但是對象實例的增加卻是很明顯的,看看下面兩張圖:

          

    這兩張圖的間隔時間2小時左右,可以發現這個對象的instance已經有了很大的增長,同時內存也吃了不少,看了看創建這個對象的Tree,發現就是poll這個方法,也就是我線程池中線程周期性掃描的結果。這期間沒有任何訪問,僅僅就是放著不動,就有如此大量的增長。我嘗試將poll(100,TimeUnit.MILLISECONDS)換成poll()全阻塞方式,對象增長依舊。因此可以看出來服務器的Memory Leak很大程度上由這部分引起,早先沒有發現,因為是SIP上線不久,沒有太多用戶,而這陣子用戶越來越多,加上API中的更新類請求比較吃內存,就容易發現此類問題。

           那么是否1.6就解決了這個問題呢,開始使用機器上1.6_01的版本,發現問題依舊,去sun下載了最新的1.6_07,發現的卻會回收,但是回收和增長都存在,具體數據描述舉例如下:

    1.       1000 instance   31k

    2.       200 instance    6k (回收了一部分)

    3.       1500 instance   46k(發現增長的比以前還多)

    4.       300 instance    9k (回收了一部分)

    5.       2000 instance   62k (發現增長的比以前還多)

    也就是說,回收時有發生,但是總體趨勢還是在上升,這個真的還需要好好測試,有興趣的同學也可以試驗一下我的測試方式,就僅僅只需要使用一個LinkedBlockingQueue,然后定時的去pool1.5絕對增長的不小。

           對于這個問題,我只能再去驗證,如果發現真的暫時不可避免,那么只有考慮替代方案了。

    這是今天作了Memory Leak的一些分享,希望也能給其他遇到或者將會遇到問題的同學一個分享,說一句,如果有條件的話用JProfiler去分析性能絕對是不錯的,沒有條件么就dump,gc輸出來查找問題。
       剛剛作了測試現在的場景可以用take來替換poll,原來是看中了poll的timeout方式,take完全沒有問題,看來如果要在1.5版本用,還是老老實實用take。

    posted on 2008-09-18 22:14 岑文初 閱讀(3931) 評論(4)  編輯  收藏

    評論

    # re: Memory Leak分析分享 2008-09-19 09:15 dennis
    LinkedBlockingQueue的這個問題在jdk1.6.2以上版本已經解決了,用jprofiler觀察下,盡管一直在增加,但是執行run gabage collector in profiled application的時候會立即減下來。  回復  更多評論
      

    # re: Memory Leak分析分享 2008-09-19 09:20 dennis
    另外poll()不是全阻塞吧,poll()如果隊列為空會返回null,take()才是全阻塞,建議用take()來做替代  回復  更多評論
      

    # re: Memory Leak分析分享 2008-09-19 09:46 文初
    對的,樓上說的是,這里寫錯了,以前用poll就是為了timeout來做半阻塞。對于jdk1.6是否解決了,我還需要在看看,在我寫的里面提到了的確看到有回收,但不知道為什么會始終在增加。沒有請求的時候也在增長,這就有點讓人擔心了?,F在用take試試看。  回復  更多評論
      

    # re: Memory Leak分析分享 2008-09-19 11:33 隔葉黃鶯
    拜讀過,很有意義,總結起來就是兩點
    1. iBatis 的Throttle作increment 有可能造成阻塞線程
    2. 1.6.2 jdk 以前的 LinkedBlockingQueue.poll() 方法會帶來內存溢出,用全阻塞的 take() 方法就能避免,或者升級 jdk 到 1.6.2 版。  回復  更多評論
      


    只有注冊用戶登錄后才能發表評論。


    網站導航:
     
    主站蜘蛛池模板: 亚洲欧美日韩中文高清www777| 国产电影午夜成年免费视频| 亚洲香蕉在线观看| 亚洲乱码中文字幕久久孕妇黑人| 高清国语自产拍免费视频国产 | 精品熟女少妇a∨免费久久| 免费人成视频在线观看免费| 亚洲一区免费视频| 日韩亚洲AV无码一区二区不卡| 久久精品国产亚洲7777| 免费A级毛片在线播放不收费| 毛片免费视频播放| 精品无码免费专区毛片| 色欲色香天天天综合网站免费| 中国一级毛片免费看视频| 成年大片免费高清在线看黄| 亚洲成av人无码亚洲成av人| 亚洲精品中文字幕无乱码麻豆| 亚洲精品福利网泷泽萝拉| 亚洲av不卡一区二区三区| 亚洲国产精品久久| 亚洲精品无码不卡| 亚洲高清在线播放| 亚洲午夜久久影院| 亚洲影院在线观看| 亚洲视频网站在线观看| 亚洲电影在线免费观看| 亚洲综合激情视频| 亚洲国产精品白丝在线观看| 久久亚洲精品人成综合网| 亚洲日本一区二区三区| 亚洲精品综合久久中文字幕 | 和日本免费不卡在线v| 国内精品免费麻豆网站91麻豆| 999久久久免费精品播放| 精品无码人妻一区二区免费蜜桃| 亚洲精品在线免费看| 99在线精品视频观看免费| 一个人看的www在线观看免费 | 亚洲人AV在线无码影院观看| 亚洲精品乱码久久久久久蜜桃图片|