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

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

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

    走在架構(gòu)師的大道上 Jack.Wang's home

    Java, C++, linux c, C#.net 技術(shù),軟件架構(gòu),領(lǐng)域建模,IT 項(xiàng)目管理 Dict.CN 在線詞典, 英語(yǔ)學(xué)習(xí), 在線翻譯

    BlogJava 首頁(yè) 新隨筆 聯(lián)系 聚合 管理
      195 Posts :: 3 Stories :: 728 Comments :: 0 Trackbacks

    摘 要 穩(wěn)定性是衡量軟件系統(tǒng)質(zhì)量的重要指標(biāo),內(nèi)存泄漏是破壞系統(tǒng)穩(wěn)定性的重要因素。由于采用垃圾回收機(jī)制,Java語(yǔ)言的內(nèi)存泄漏的模式與C++等語(yǔ)言相比有很大的不同。全文通過(guò)與C++中的內(nèi)存泄漏問(wèn)題進(jìn)行對(duì)比,講述了Java內(nèi)存泄漏的基本原理,以及如何借助Optimizeit profiler工具來(lái)測(cè)試內(nèi)存泄漏和分析內(nèi)存泄漏的原因,在實(shí)踐中證明這是一套行之有效的方法。

    關(guān)鍵詞Java; 內(nèi)存泄漏; GC(垃圾收集器) 引用; Optimizeit


    問(wèn)題的提出
      筆者曾經(jīng)參與開(kāi)發(fā)的網(wǎng)管系統(tǒng),系統(tǒng)規(guī)模龐大,涉及上百萬(wàn)行代碼。系統(tǒng)主要采用Java語(yǔ)言開(kāi)發(fā),大體上分為客戶端、服務(wù)器和數(shù)據(jù)庫(kù)三個(gè)層次。在版本進(jìn)入測(cè)試和試用的過(guò)程中,現(xiàn)場(chǎng)人員和測(cè)試部人員紛紛反映:系統(tǒng)的穩(wěn)定性比較差,經(jīng)常會(huì)出現(xiàn)服務(wù)器端運(yùn)行一晝夜就死機(jī)的現(xiàn)象,客戶端跑死的現(xiàn)象也比較頻繁地發(fā)生。對(duì)于網(wǎng)管系統(tǒng)來(lái)講,經(jīng)常性的服務(wù)器死機(jī)是個(gè)比較嚴(yán)重的問(wèn)題,因?yàn)轭l繁的死機(jī)不僅可能導(dǎo)致前后臺(tái)數(shù)據(jù)不一致,發(fā)生錯(cuò)誤,更會(huì)引起用戶的不滿,降低客戶的信任度。因此,服務(wù)器端的穩(wěn)定性問(wèn)題必須盡快解決。
    解決思路
      通過(guò)察看服務(wù)器端日志,發(fā)現(xiàn)死機(jī)前服務(wù)器端頻繁拋出OutOfMemoryException內(nèi)存溢出錯(cuò)誤,因此初步把死機(jī)的原因定位為內(nèi)存泄漏引起內(nèi)存不足,進(jìn)而引起內(nèi)存溢出錯(cuò)誤。如何查找引起內(nèi)存泄漏的原因呢?有兩種思路:第一種,安排有經(jīng)驗(yàn)的編程人員對(duì)代碼進(jìn)行走查和分析,找出內(nèi)存泄漏發(fā)生的位置;第二種,使用專門的內(nèi)存泄漏測(cè)試工具Optimizeit進(jìn)行測(cè)試。這兩種方法都是解決系統(tǒng)穩(wěn)定性問(wèn)題的有效手段,使用內(nèi)存測(cè)試工具對(duì)于已經(jīng)暴露出來(lái)的內(nèi)存泄漏問(wèn)題的定位和解決非常有效;但是軟件測(cè)試的理論也告訴我們,系統(tǒng)中永遠(yuǎn)存在一些沒(méi)有暴露出來(lái)的問(wèn)題,而且,系統(tǒng)的穩(wěn)定性問(wèn)題也不僅僅只是內(nèi)存泄漏的問(wèn)題,代碼走查是提高系統(tǒng)的整體代碼質(zhì)量乃至解決潛在問(wèn)題的有效手段。基于這樣的考慮,我們的內(nèi)存穩(wěn)定性工作決定采用代碼走查結(jié)合測(cè)試工具的使用,雙管齊下,爭(zhēng)取比較徹底地解決系統(tǒng)的穩(wěn)定性問(wèn)題。
      在代碼走查的工作中,安排了對(duì)系統(tǒng)業(yè)務(wù)和開(kāi)發(fā)語(yǔ)言工具比較熟悉的開(kāi)發(fā)人員對(duì)應(yīng)用的代碼進(jìn)行了交叉走查,找出代碼中存在的數(shù)據(jù)庫(kù)連接聲明和結(jié)果集未關(guān)閉、代碼冗余和低效等故障若干,取得了良好的效果,文中主要講述結(jié)合工具的使用對(duì)已經(jīng)出現(xiàn)的內(nèi)存泄漏問(wèn)題的定位方法。

    內(nèi)存泄漏的基本原理

      在C++語(yǔ)言程序中,使用new操作符創(chuàng)建的對(duì)象,在使用完畢后應(yīng)該通過(guò)delete操作符顯示地釋放,否則,這些對(duì)象將占用堆空間,永遠(yuǎn)沒(méi)有辦法得到回收,從而引起內(nèi)存空間的泄漏。如下的簡(jiǎn)單代碼就可以引起內(nèi)存的泄漏:

    根據(jù)這樣的基本假設(shè),我們可以持續(xù)地觀察系統(tǒng)運(yùn)行時(shí)使用的內(nèi)存的大小和各實(shí)例的個(gè)數(shù),如果內(nèi)存的大小持續(xù)地增長(zhǎng),則說(shuō)明系統(tǒng)存在內(nèi)存泄漏,如果某個(gè)類的實(shí)例的個(gè)數(shù)持續(xù)地增長(zhǎng),則說(shuō)明這個(gè)類的實(shí)例可能存在泄漏情況。

      Optimizeit是Borland公司的產(chǎn)品,主要用于協(xié)助對(duì)軟件系統(tǒng)進(jìn)行代碼優(yōu)化和故障診斷,其功能眾多,使用方便,其中的OptimizeIt Profiler主要用于內(nèi)存泄漏的分析。Profiler的堆視圖(如圖4)就是用來(lái)觀察系統(tǒng)運(yùn)行使用的內(nèi)存大小和各個(gè)類的實(shí)例分配的個(gè)數(shù)的,其界面如圖四所示,各列自左至右分別為類名稱、當(dāng)前實(shí)例個(gè)數(shù)、自上個(gè)標(biāo)記點(diǎn)開(kāi)始增長(zhǎng)的實(shí)例個(gè)數(shù)、占用的內(nèi)存空間的大小、自上次標(biāo)記點(diǎn)開(kāi)始增長(zhǎng)的內(nèi)存的大小、被釋放的實(shí)例的個(gè)數(shù)信息、自上次標(biāo)記點(diǎn)開(kāi)始增長(zhǎng)的內(nèi)存的大小被釋放的實(shí)例的個(gè)數(shù)信息,表的最后一行是匯總數(shù)據(jù),分別表示目前JVM中的對(duì)象實(shí)例總數(shù)、實(shí)例增長(zhǎng)總數(shù)、內(nèi)存使用總數(shù)、內(nèi)存使用增長(zhǎng)總數(shù)等。 
      在實(shí)踐中,可以分別在系統(tǒng)運(yùn)行四個(gè)小時(shí)、八個(gè)小時(shí)、十二個(gè)小時(shí)和二十四個(gè)小時(shí)時(shí)間點(diǎn)記錄當(dāng)時(shí)的內(nèi)存狀態(tài)(即抓取當(dāng)時(shí)的內(nèi)存快照,是工具提供的功能,這個(gè)快照也是供下一步分析使用),找出實(shí)例個(gè)數(shù)增長(zhǎng)的前十位的類,記錄下這十個(gè)類的名稱和當(dāng)前實(shí)例的個(gè)數(shù)。在記錄完數(shù)據(jù)后,點(diǎn)擊Profiler中右上角的Mark按鈕,將該點(diǎn)的狀態(tài)作為下一次記錄數(shù)據(jù)時(shí)的比較點(diǎn)。

      Java<a href='/html/xueyuan/gongjuruanjianjiaocheng/xitonggongjujiaocheng' /><u>系統(tǒng)</u></a>中內(nèi)存泄漏測(cè)試方法的<a href='/html/xueyuan/wangzhanyunyingjiaocheng/yanjiubaodao'><u>研究</u></a>(圖四)
      圖4 Profiler 堆視圖

            系統(tǒng)運(yùn)行二十四小時(shí)以后可以得到四個(gè)內(nèi)存快照。對(duì)這四個(gè)內(nèi)存快照進(jìn)行綜合分析,如果每一次快照的內(nèi)存使用都比上一次有增長(zhǎng),可以認(rèn)定系統(tǒng)存在內(nèi)存泄漏,找出在四個(gè)快照中實(shí)例個(gè)數(shù)都保持增長(zhǎng)的類,這些類可以初步被認(rèn)定為存在泄漏。
    分析與定位

      通過(guò)上面的數(shù)據(jù)收集和初步分析,可以得出初步結(jié)論:系統(tǒng)是否存在內(nèi)存泄漏和哪些對(duì)象存在泄漏(被泄漏),如果結(jié)論是存在泄漏,就可以進(jìn)入分析和定位階段了。

      前面已經(jīng)談到Java中的內(nèi)存泄漏就是無(wú)意識(shí)的對(duì)象保持,簡(jiǎn)單地講就是因?yàn)榫幋a的錯(cuò)誤導(dǎo)致了一條本來(lái)不應(yīng)該存在的引用鏈的存在(從而導(dǎo)致了被引用的對(duì)象無(wú)法釋放),因此內(nèi)存泄漏分析的任務(wù)就是找出這條多余的引用鏈,并找到其形成的原因。前面還講到過(guò)牽引對(duì)象,包括已經(jīng)加載的類的靜態(tài)變量和處于活動(dòng)線程的堆棧空間的變量。由于活動(dòng)線程的堆棧空間是迅速變化的,處于堆棧空間內(nèi)的牽引對(duì)象集合是迅速變化的,而作為類的靜態(tài)變量的牽引對(duì)象的集合在系統(tǒng)運(yùn)行期間是相對(duì)穩(wěn)定的。

      對(duì)每個(gè)被泄漏的實(shí)例對(duì)象,必然存在一條從某個(gè)牽引對(duì)象出發(fā)到達(dá)該對(duì)象的引用鏈。處于堆棧空間的牽引對(duì)象在被從棧中彈出后就失去其牽引的能力,變?yōu)榉菭恳龑?duì)象,因此,在長(zhǎng)時(shí)間的運(yùn)行后,被泄露的對(duì)象基本上都是被作為類的靜態(tài)變量的牽引對(duì)象牽引。
     Profiler的內(nèi)存視圖除了堆視圖以外,還包括實(shí)例分配視圖(圖5)和實(shí)例引用圖(圖6)。
     Profiler的實(shí)例引用圖為找出從牽引對(duì)象到泄漏對(duì)象的引用鏈提供了非常直接的方法,其界面的第二個(gè)欄目中顯示的就是從泄漏對(duì)象出發(fā)的逆向引用鏈。需要注意的是,當(dāng)一個(gè)類的實(shí)例存在泄漏時(shí),并非其所有的實(shí)例都是被泄漏的,往往只有一部分是被泄漏對(duì)象,其它則是正常使用的對(duì)象,要判斷哪些是正常的引用鏈,哪些是不正常的引用鏈(引起泄漏的引用鏈)。通過(guò)抽取多個(gè)實(shí)例進(jìn)行引用圖的分析統(tǒng)計(jì)以后,可以找出一條或者多條從牽引對(duì)象出發(fā)的引用鏈,下面的任務(wù)就是找出這條引用鏈形成的原因。
     實(shí)例分配圖提供的功能是對(duì)每個(gè)類的實(shí)例的分配位置進(jìn)行統(tǒng)計(jì),查看實(shí)例分配的統(tǒng)計(jì)結(jié)果對(duì)于分析引用鏈的形成具有一定的作用,因?yàn)檎业椒峙滏溑c引用鏈的交點(diǎn)往往就可以找到了引用鏈形成的原因,下面將具體介紹。

    Java<a href='/html/xueyuan/gongjuruanjianjiaocheng/xitonggongjujiaocheng' /><u>系統(tǒng)</u></a>中內(nèi)存泄漏測(cè)試方法的<a href='/html/xueyuan/wangzhanyunyingjiaocheng/yanjiubaodao'><u>研究</u></a>(圖五)
      圖5 實(shí)例分配圖

      Java<a href='/html/xueyuan/gongjuruanjianjiaocheng/xitonggongjujiaocheng' /><u>系統(tǒng)</u></a>中內(nèi)存泄漏測(cè)試方法的<a href='/html/xueyuan/wangzhanyunyingjiaocheng/yanjiubaodao'><u>研究</u></a>(圖六)

      
      圖6 實(shí)例引用圖

      設(shè)想一個(gè)實(shí)例對(duì)象a在方法f中被分配,最終被實(shí)例對(duì)象b所引用,下面來(lái)分析從b到a的引用鏈可能的形成原因。方法f在創(chuàng)建對(duì)象a后,對(duì)它的使用分為四種情況:1、將a作為返回值返回;2、將a作為參數(shù)調(diào)用其它方法;3、在方法內(nèi)部將a的引用傳遞給其它對(duì)象;4、其它情況。其中情況4不會(huì)造成由b到a的引用鏈的生成,不用考慮。下面考慮其它三種情況:對(duì)于1、2兩種情況,其造成的結(jié)果都是在另一個(gè)方法內(nèi)部獲得了對(duì)象a的引用,它的分析與方法f的分析完全一樣(遞歸分析);考慮第3種情況:1、假設(shè)方法f直接將對(duì)象a的引用加入到對(duì)象b,則對(duì)象b到a的引用鏈就找到了,分析結(jié)束;2、假設(shè)方法f將對(duì)象a的引用加入到對(duì)象c,則接下來(lái)就需要跟蹤對(duì)象c的使用,對(duì)象c的分析比對(duì)象a的分析步驟更多一些,但大體原理都是一樣的,就是跟蹤對(duì)象從創(chuàng)建后被使用的歷程,最終找到其被牽引對(duì)象引用的原因。

      現(xiàn)在將泄漏對(duì)象的引用鏈以及引用鏈形成的原因找到了,內(nèi)存泄漏測(cè)試與分析的工作就到此結(jié)束,接下來(lái)的工作就是修改相應(yīng)的設(shè)計(jì)或者實(shí)現(xiàn)中的錯(cuò)誤了。

    總結(jié)

      使用上述的測(cè)試和分析方法,在實(shí)踐中先后進(jìn)行了三次測(cè)試,找出了好幾處內(nèi)存泄漏錯(cuò)誤。系統(tǒng)的穩(wěn)定性得到很大程度的提高,最初運(yùn)行1~2天就拋出內(nèi)存溢出異常,修改完成后,系統(tǒng)從未出現(xiàn)過(guò)內(nèi)存溢出異常。此方法適用于任何使用Java語(yǔ)言開(kāi)發(fā)的、對(duì)穩(wěn)定性有比較高要求的軟件系統(tǒng)。


    原文地址:http://www.it55.com/html/xueyuan/chengxukaifa/JAVAjiaocheng/20070719/111179_2.html
       



    本博客為學(xué)習(xí)交流用,凡未注明引用的均為本人作品,轉(zhuǎn)載請(qǐng)注明出處,如有版權(quán)問(wèn)題請(qǐng)及時(shí)通知。由于博客時(shí)間倉(cāng)促,錯(cuò)誤之處敬請(qǐng)諒解,有任何意見(jiàn)可給我留言,愿共同學(xué)習(xí)進(jìn)步。
    posted on 2008-09-27 09:19 Jack.Wang 閱讀(908) 評(píng)論(0)  編輯  收藏 所屬分類: 計(jì)算機(jī)論文
    主站蜘蛛池模板: 亚洲精品人成无码中文毛片 | 亚洲人成网站在线观看播放动漫| 精品亚洲成α人无码成α在线观看| 日本无卡码免费一区二区三区| 女人让男人免费桶爽30分钟| 在线观看免费人成视频| 精品无码人妻一区二区免费蜜桃 | 国产亚洲欧洲Aⅴ综合一区 | 99精品视频在线视频免费观看| 免费国产午夜高清在线视频| 亚洲av无码一区二区三区人妖 | 日韩va亚洲va欧洲va国产| 亚洲无码在线播放| 免费的一级黄色片| 全免费a级毛片免费看不卡| 成年女人午夜毛片免费看| 久久久久久久岛国免费播放| 国产精品成人亚洲| 一级做a爰性色毛片免费| 亚洲va在线va天堂成人| 亚洲AV无码1区2区久久| 久久亚洲国产精品五月天| 亚洲国产综合精品中文第一区| 亚洲麻豆精品果冻传媒| 亚洲一区中文字幕在线观看| 国产精品亚洲自在线播放页码| 亚洲男同gay片| 免费精品国自产拍在线播放| 99999久久久久久亚洲| 亚洲精品一卡2卡3卡四卡乱码| 亚洲成在人线aⅴ免费毛片| 日韩大片在线永久免费观看网站| 香蕉免费看一区二区三区| 黄页视频在线观看免费| 精品久久久久久无码免费| 99久热只有精品视频免费看| 最近高清中文字幕无吗免费看| 99久久99久久精品免费观看| 免费无码又黄又爽又刺激| www.黄色免费网站| 国产一区二区免费在线|