專利名稱:基于分區(qū)的診斷Java系統(tǒng)的內(nèi)存泄漏的方法及裝置的制作方法
技術(shù)領(lǐng)域:
本發(fā)明涉及對Java系統(tǒng)的內(nèi)存泄漏的診斷技術(shù),具體地,涉瓦基于分 區(qū)的診斷Java系統(tǒng)的內(nèi)存泄漏的方法及裝置。
背景技術(shù):
Java系統(tǒng)的一個重要的優(yōu)點在于通過垃圾收集器自動管理內(nèi)存的回 收,程序員不需要通過調(diào)用函數(shù)來釋放內(nèi)存。Java的內(nèi)存管理是指對象的 分配和釋放。在Java中,需要通過程序為每個對象申請內(nèi)存空間,所有對 象都在堆內(nèi)存中分配空間,而對象的釋放由垃圾收集器決定和執(zhí)行。因此, 在Java中,內(nèi)存的分配由程序完成,而內(nèi)存的釋放由垃圾收集器完成,這 樣,程序員無需擔心內(nèi)存的釋放問題。
然而,Java程序可能非故意地保留對某些不再使用的對象的引用, 4吏得Java系統(tǒng)中的垃圾收集器不能回收這些對象所占的內(nèi)存空間,導致所 謂的"內(nèi)存泄漏"。內(nèi)存泄漏會引起Java系統(tǒng)的性能下降,嚴重地甚至會 導致程序無法運行或者系統(tǒng)死機。例如,對使用IBM J2EE電子商務軟件 的客戶進行的調(diào)查顯示,由于內(nèi)存泄漏,常常導致生產(chǎn)系統(tǒng)崩潰。因此, 診斷Java系統(tǒng)的內(nèi)存泄漏,即找出相關(guān)的類(class)和方法(method) 等,變得很重要。
在現(xiàn)有才支術(shù)中,存在以下幾種與內(nèi)存泄漏有關(guān)的方法 (1)第一種方法是對任務進行內(nèi)存計算和控制,這可以防止一個 任務在運行期間耗盡整個內(nèi)存。在多任務虛擬機(MVM)中,每個任務 都具有一定的被確保的內(nèi)存量,Kaffe操作系統(tǒng)(KaffeOS)在每一個進程 的S^出上計算CPU和內(nèi)存的消耗量。通過計算和控制內(nèi)存消耗量,即使出
現(xiàn)內(nèi)存泄漏,具有泄漏邏輯的任務或進程也不會獨占整個堆內(nèi)存。這種方 法可以在出現(xiàn)內(nèi)存泄漏的情況下改善運行應用程序的可用性,但是它并不 能辨識出內(nèi)存泄漏的原因,也不能幫助用戶找到與內(nèi)存泄漏有關(guān)的源代碼。
關(guān)于上述方法和Kaffe操作系統(tǒng)的具體詳情可參見Czajkowski, G.,和 Dayn es, L.所發(fā)表的"Multitasking without compromise: a virtual machine evolution" , Object-Oriented Programming, Systems, Languages, and Applications (OOPSLA,Ol), 2001年11月和G. Back, W. Hsieh和J. Lepreau所發(fā)表的"Processes in KaffeOS: Isolation, resource management, and sharing in Java" , Proceedings of the Fourth Symposium on Operating System Design and Implementation (OSDI,2000),圣地亞哥,加州,美國, 2000年。
(2) 第二種方法是根據(jù)某些特征和規(guī)則對源代碼進行靜態(tài)或基于 簡檔的分析,以發(fā)現(xiàn)潛在的內(nèi)存泄漏。目前,研究人員對這一類方法已經(jīng) 進行了大量的探索,例如參見R. Shaham, E. K. Kolodner和M. Sagiv所發(fā) 表的"Automatic removal of array memory leaks in Java" , D. A. Watt, Editor, Compiler Construction, 9 International Conference, Volume 1781 of Lecture Notes in Computer Science,第50-66頁,柏林,德國,2000年3 月和T. Chilimbi和M. Hauswirth所發(fā)表的"Low-overhead memory leak detection using adaptive statistical profiling" , Proceedings of the Symposium on Architectural Support for Proramming Languages and Operating Systems (ASPLOS), 2004年10月。
但是在Java中,內(nèi)存泄漏實際上是語義相關(guān)的,因此,對特征和規(guī)則 的定義很困難,并且不正確的定義會導致錯誤的報告。而且,如果沒有強 調(diào)方法對象調(diào)用的時間順序,則#^確定變量是否引用了泄漏對象。
(3) 第三種方法是基于運行信息的方法,其分析堆內(nèi)存的快照,以 選出泄漏對象的候選。具體詳情可參見Nick Mitchell和Gary Sevitsky所 發(fā)表的"LeakBot: An Automated and Lightweight Tool for Diagnosing Memory Leaks in Large Java Applications" , European Conference onObject-oriented Computing (ECOOP) , 2003年7月。然而該方法產(chǎn)生 大量的有關(guān)各個對象的低級別的信息,這需要大量的分析時間,并且無法 幫助用戶找到與內(nèi)存泄漏有關(guān)的源代碼。
發(fā)明內(nèi)容
本發(fā)明正是基于上述技術(shù)問題而提出的,其目的在于提供一種基于分 區(qū)的診斷Java系統(tǒng)的內(nèi)存泄漏的方法和裝置,可以快速地診斷內(nèi)存泄漏, 防止系統(tǒng)由于內(nèi)存泄漏而崩潰,并能找出引起內(nèi)存泄漏的源代碼,方便了 對內(nèi)存泄漏的修復。
根據(jù)本發(fā)明的一個方面,提供一種基于分區(qū)的診斷Java系統(tǒng)的內(nèi)存泄 漏的方法,包括根據(jù)分區(qū)策略,將Java虛擬機的堆內(nèi)存劃分成多個分區(qū), 其中每個分區(qū)具有至少一個分區(qū)所有者;檢測上述各個分區(qū)的狀態(tài)以確定 是否存在某一個分區(qū)的內(nèi)存空間祐恭 S以及如果存在,則判斷為該分區(qū) 可能存在內(nèi)存泄漏,分析該分區(qū)以獲取泄漏對象和與泄漏對象關(guān)聯(lián)的對象。
根據(jù)本發(fā)明的另 一個方面,提供一種基于分區(qū)的診斷Java系統(tǒng)的內(nèi)存 泄漏的裝置,包括分區(qū)單元,用于根據(jù)分區(qū)策略,將Java虛擬機的堆內(nèi) 存劃分成多個分區(qū),其中每個分區(qū)具有至少一個分區(qū)所有者;檢測器,用 于檢測上述各個分區(qū)的狀態(tài)以確定是否存在某一個分區(qū)的內(nèi)存空間被耗 盡;以及分析器,用于分析內(nèi)存空間祐來盡的分區(qū)以獲取泄漏對象和與泄 漏對象關(guān)聯(lián)的對象。
圖1是根據(jù)本發(fā)明的一個實施例的基于分區(qū)的診斷Java系統(tǒng)的內(nèi)存泄 漏的方法的流程圖2是根據(jù)本發(fā)明的另一個實施例的基于分區(qū)的診斷Java系統(tǒng)的內(nèi)存 泄漏的方法的流程圖3是示出兩個分區(qū)所有者的示意圖4是基于J9虛擬機內(nèi)存空間的分區(qū)的結(jié)構(gòu)的示意圖5是示出通過JVM TI標簽實現(xiàn)的堆內(nèi)存的分區(qū)的示意圖; 圖6是根據(jù)本發(fā)明的實施例的基于分區(qū)的診斷Java系統(tǒng)的內(nèi)存泄漏的 裝置的方框圖。
具體實施例方式
相信通過下面結(jié)合附圖對本發(fā)明的具體實施方式
的詳細說明,本發(fā)明 的上述和其它目的、特征和優(yōu)點將變得更加明顯。
圖1是才艮據(jù)本發(fā)明的一個實施例的基于分區(qū)的診斷Java系統(tǒng)的內(nèi)存泄 漏的方法的流程圖。
如圖1所示,首先在步驟110,根據(jù)分區(qū)策略,Java虛擬機的堆內(nèi)存 被劃分成多個分區(qū),其中每個分區(qū)具有至少一個分區(qū)所有者。
分區(qū)策略是用于定義分區(qū)所有者的配置文件,其相應地定義分區(qū)和分 區(qū)的大小。因此,分區(qū)策略至少包含分區(qū)所有者和分區(qū)的大小。作為一個 分區(qū)的分區(qū)所有者,其創(chuàng)建的對象都被分配在該分區(qū)中。
分區(qū)策略可以預先由用戶生成,也可以通過分析源程序代碼確定。具 體的生成分區(qū)策略的方法,將在后面的實施例中詳細描述。
這樣,在分區(qū)策略的基礎(chǔ)上,Java虛擬機的堆內(nèi)存可以進行分區(qū)操作。 關(guān)于Java虛擬機的堆內(nèi)存的分區(qū)操作,將在后面的實施例中詳細描述。
然后,在步驟120,檢測被劃分的各個分區(qū)的狀態(tài)以確定是否存在某 一個分區(qū)的內(nèi)存空間被*。通過檢測分區(qū)的狀態(tài),可以知道每個分區(qū)的 使用情況。當某一個分區(qū)的內(nèi)存空間將被*時,對該分區(qū)的對象分配請 求會產(chǎn)生內(nèi)存溢出錯誤(OutOfMemoryError)信號。因此,通過檢測該 信號是否出現(xiàn),可以知道分區(qū)的內(nèi)存空間是否^L^。
當存在某一個分區(qū)的內(nèi)存空間被*時,判斷為在該分區(qū)可能存在內(nèi) 存泄漏。然后,在步驟130,進一步分析該分區(qū),以獲取泄漏對象和與泄 漏對象關(guān)聯(lián)的對象。例如,可以采用現(xiàn)有工具中的LeakBot分析分區(qū)。
在本實施例中,泄漏對象是指在發(fā)生內(nèi)存泄漏時被引用的時間比所需 要的時間長的對象,與泄漏對象關(guān)聯(lián)的對象包括直接或間接引用泄漏對
象的對象和/或創(chuàng)建泄漏對象的對象。
如果不存在某一個分區(qū)的內(nèi)存空間^^,則重復執(zhí)行步驟120。
通過以上描述可以看出,本實施例的基于分區(qū)的診斷Java系統(tǒng)的內(nèi)存 泄漏的方法通過對Java虛擬機的堆內(nèi)存進行分區(qū)并檢測這些分區(qū)的內(nèi)存 空間是否耗盡,可以直接而快速地診斷Java系統(tǒng)是否存在內(nèi)存泄漏,并且, 通過堆內(nèi)存的分區(qū),使得在某一個分區(qū)中的內(nèi)存泄漏不會影響其它分區(qū)的 運行,從而使整個Java虛擬機也能夠保持運行。
圖2是根據(jù)本發(fā)明的另 一個實施例的基于分區(qū)的診斷Java系統(tǒng)的內(nèi)存 泄漏的方法的流程圖。下面結(jié)合附圖詳細i兌明本實施例。
如圖2所示,首先,在步驟101,生成或者獲取Java虛擬機的堆內(nèi)存 的分區(qū)策略。如上所述,分區(qū)策略是用于定義分區(qū)所有者的配置文件,其 相應地定義分區(qū)和分區(qū)的大小。因此,分區(qū)策略至少包含分區(qū)所有者和分 區(qū)的大小。作為一個分區(qū)的分區(qū)所有者,其創(chuàng)建的對象都被分配在該分區(qū) 中。分區(qū)所有者可以是Java中的包(package)、類(class )或者方法(me仇od) 等。
分區(qū)策略可以由用戶預先根據(jù)其目的生成。通常,分區(qū)是基于應用程 序的邏輯結(jié)構(gòu)而定義的,例如,在J2EE應用程序中,可以將每個Servlet (小服務程序)和EJB (Java企業(yè)構(gòu)件)定義為分區(qū)所有者,那么,由這 些分區(qū)所有者創(chuàng)建的對象都在對應的分區(qū)內(nèi)分配內(nèi)存。然后,才艮據(jù)所獲取 的分區(qū)所有者的行為,可以確定各個分區(qū)的大小。由于每個分區(qū)所有者的 各自的行為對其所使用的內(nèi)存空間的影響較大,因此,通常需要一組測試 用例來確定合適的分區(qū)大小。
可選地,還可以通過分析應用程序的源代碼來生成分區(qū)策略。具體地, 首先,對應用程序的源代碼執(zhí)行逃逸(escape)分析以獲取源代碼中所有 對象之間關(guān)于內(nèi)存泄漏的潛在關(guān)系。通俗地說,對象逃逸是指對象的生命 周期超過了創(chuàng)建該對象的對象,例如線程或方法等。關(guān)于對象的逃逸的正 式定義可參照J. Choi, M. Gupta, M. Serrano, V. Sreedhar和S. Midkiff所 著的"Escape analysis for Java" , In Object-Oriented Programming, System
Languages and Applications, 1999。導致對象逃逸的原因是存在沒有在引 用目標對象的對象中創(chuàng)建的對象。然后,根據(jù)逃逸分析的結(jié)果,計算每兩 個對象之間的距離,并且根據(jù)所計算的距離,將所有對象聚類成多個組, 并為每個組分配一個內(nèi)存空間,即分區(qū)。在本實施例中,聚類可以釆用譜 聚類方法,可參見A, Y. Ng, M. Jordan和Y. Weiss所著的"On Spectral Clustering: Analysis and an Algorithm ,, , In Advances in Neural Information Processing Systems, 2001。最后,才艮據(jù)每個分區(qū)所包含的對象, 確定每個分區(qū)的分區(qū)所有者及其大小。 下面通過具體的實例說明分區(qū)策略。
實例1:示出了在方法級別上定義一個分區(qū)所有者的分區(qū)策略的例子。 如下所示的分區(qū)策略定義了一個分區(qū),其名稱為"HelloPar",大小為10K, 其分區(qū)所有者是類com.ibm.jpar.runtime.test.HelloWorld的方法say (String)。
<partition>
<name>HelloPar</name>
<size>10000</size>
<methods>
<class-name〉com.ibm.jpar.runtime.test.HelloWorld</class-name> <method-name>say</method-name> <method-params>java.lang.String</method-params> </methods>
</partition>
當運行應用程序時,在方法say (String)條目處,線程綁定分區(qū)被跳 轉(zhuǎn)到屬于該分區(qū)所有者say (String)的分區(qū)。
實例2:示出了一個分區(qū)具有多個分區(qū)所有者的分區(qū)策略的例子。如 下所示的分區(qū)策略定義了具有兩個分區(qū)所有者的分區(qū),其中一個分區(qū)所有 者是類com.ibm.jpar.runtime.test.HelloWorld的方法say ( String),另一 個分區(qū)戶斤有者是類com.ibm.jpar.runtime.test.HelloWorld的方,法echo。
<partition>
<name〉HelloEchoPar</name〉
<size>20000</size>
<methods〉
<class-name>com.ibm.jpar.runtime.test.HelloWorld</class-name〉
<method-name>say</method-name>
<method-params>java.lang.String</niethod-params> </methods> <methods>
<class-name>com.ibmjpar.runtinie.test.Echo</class-name> <method-name>echo</method-name> <method-params>java.lang.String</niethocl-params〉 </methods>
</parthion〉
實例3:示出了在類級別上定義分區(qū)或者分區(qū)所有者的分區(qū)策略的例 子。為了在更高級別(例如,類級別)上定義分區(qū)或者分區(qū)所有者,需要 使用通配符wildcard(*)。如下所示的分區(qū)策略定義了分區(qū)所有者是類 com.ibm.jpar.tuntime,test.HelloWoiid的分區(qū)。
<partition>
<name>HelloPar</name>
<size>15000</size>
<methods>
<class-name〉com.ibm.jpar.runtime.test.HenoWorld</class-name> <method-name>*</method-name> <method-params〉*</method-params〉 </methods>
</partition>
返回圖2,在生成或者獲取了分區(qū)策略(步驟101)之后,根據(jù)該分區(qū)
策略,Java虛擬機的堆內(nèi)存可以被劃分成多個分區(qū)(步驟110)。
例如,如果分區(qū)策略是線程綁定的策略,那么,分區(qū)是與線程綁定的 內(nèi)存空間,分區(qū)所有者是線程,且由各線程創(chuàng)建的所有對象都被分配在該 線程綁定分區(qū)中。如果在應用程序運行時,當前線程執(zhí)行了另一個分區(qū)所 有者的方法,則線程綁定分區(qū)和分區(qū)所有者將改變。圖3示出了兩個分區(qū) 所有者的示意圖。如圖3所示,Java虛擬機堆內(nèi)存被劃分成兩個分區(qū)分 區(qū)1和分區(qū)2。分區(qū)1的分區(qū)所有者1創(chuàng)建了 5個對象,這5個對象都被 分配在分區(qū)1中。分區(qū)1中的對象5創(chuàng)建分區(qū)2的分區(qū)所有者2,則線程 綁定分區(qū)被跳轉(zhuǎn)到分區(qū)2,分區(qū)所有者2創(chuàng)建2個對象,這2個對象都分 配在分區(qū)2中。
下面詳細描述了兩種實現(xiàn)堆內(nèi)存的分區(qū)的方式,當然,本領(lǐng)域的技術(shù) 人員知道還可以采用其它方式實現(xiàn)堆內(nèi)存的分區(qū)。 實施方式l:基于J9虛擬機內(nèi)存空間的實現(xiàn)
圖4是基于J9虛擬機內(nèi)存空間的分區(qū)的結(jié)構(gòu)的示意圖。J9虛擬機的 內(nèi)存空間機制^Jt合于堆內(nèi)存的分區(qū)。作為堆內(nèi)存分配的單元的內(nèi)存空間 管理直接處理對象分配請求的物理內(nèi)存. 一個內(nèi)存空間不能使用其它內(nèi)存 空間的物理內(nèi)存。J9虛擬機中的資源管理類庫jclRM提供內(nèi)存空間的應用 程序編程接口 (API)以進行一些基本的管理^Mt,包括內(nèi)存空間的創(chuàng)建、 解構(gòu)等。
如圖4所示,在該分區(qū)結(jié)構(gòu)中,有4個分區(qū)所有者,分區(qū)所有者是線 程。如上所述,在分區(qū)策略中定義了分區(qū)所有者和相應的內(nèi)存空間(分區(qū)) 的大小。那么,根據(jù)分區(qū)策略,可以在應用程序起動時,經(jīng)由資源管理類 庫jc股M通過調(diào)用createMemeorySpace (創(chuàng)建內(nèi)存空間)方法來分別創(chuàng) 建與各個分區(qū)所有者對應的內(nèi)存空間(分區(qū)),其大小如分區(qū)策略中所定
義的。這樣,每個線程都與一個內(nèi)存空間相關(guān)聯(lián),由一個線程所創(chuàng)建的所 有對象將被分配在與該線程相關(guān)聯(lián)的內(nèi)存空間中。
在圖4所示的結(jié)構(gòu)中,在應用程序的線程與對應的內(nèi)存空間(分區(qū)) 之間,還存在線程-內(nèi)存空間跳轉(zhuǎn)器(TMSS) 。 TMSS包括注入在Java虛擬機中裝載的類的構(gòu)件。所注入的代碼可以經(jīng)由資源管理類庫jclRM提 供的接口通過調(diào)用setCurrentMemeorySpace(設(shè)置當前內(nèi)存空間)方法來 跳轉(zhuǎn)線程綁定的內(nèi)存空間。每當應用程序的執(zhí)行路徑通過一個分區(qū)所有者 與另一個分區(qū)所有者的邊界時,TMSS觸發(fā)所注入的代碼以跳轉(zhuǎn)線程綁定 的內(nèi)存空間。
因此,應用程序運行時的工作流程如下首先,起動應用程序,讀取 分區(qū)策略,并對分區(qū)策略中的每個分區(qū)所有者創(chuàng)建內(nèi)存空間作為分區(qū)。接 著,注入分區(qū)所有者的類,插入線程綁定的內(nèi)存空間代碼,然后調(diào)用應用 程序的主方法。當應用程序停止時,所有的內(nèi)存空間也可以經(jīng)由資源管理 類庫jclRM接口通過調(diào)用destroyMemorySpaces (釋放內(nèi)存空間)方法來 解構(gòu)。
實施方式2:基于Java虛擬機工具接口的實現(xiàn)
Java虛擬機工具接口 (JVM TI)是由開發(fā)和監(jiān)視工具使用的編程接 口,其可以檢查在Java虛擬機中運行的應用程序的狀態(tài)和控制應用程序的 執(zhí)行,并且JVM TI提供了 一組在運行時允許與對象一起操作的堆接口 。
JVM TI使得對象可以與一個值(標簽)相關(guān)聯(lián),該標簽可以通過使 用SetTag (設(shè)置標簽)方法或者通過諸如jvmtiHeapObjectCallback的回 調(diào)方法設(shè)置。這樣,堆內(nèi)存的分區(qū)可以通過使用標簽來實現(xiàn)。首先,每個 分區(qū)被提供一個標識符ID,那么,僅當一個對象附帶有具有某個分區(qū)的分 區(qū)ID的標簽時,才表示該對象屬于該分區(qū)。
在運行應用程序時,在堆內(nèi)存中的一個分區(qū)中的對象可以不在一個連 續(xù)的內(nèi)存空間內(nèi),而是通過標簽聚集在一起。圖5是示出通過JVM TI標 簽實現(xiàn)的堆內(nèi)存的分區(qū)的示意圖。如圖5所示,與值為l的標簽對應的對 象地址都屬于分區(qū)1,與值為2的標簽對應的對象地址都屬于分區(qū)2,與值 為3的標簽對應的對象地址都屬于分區(qū)3,盡管在同一個分區(qū)中的對象的 地址不是連續(xù)的。
分區(qū)的已4吏用大小可以通過由JVMTl接口調(diào)用GetObjectsWithTags (獲取具有標簽的對象)方法獲取該分區(qū)中所有的對象及其大小來獲得.
因此,基于Java虛擬機工具接口實現(xiàn)的線程綁定分區(qū)可以通過如下步 驟實現(xiàn)在應用程序運行時,動態(tài)地創(chuàng)建具有標識符ID的分區(qū),使得對 每一個線程都有一個線程綁定分區(qū);每當分配一個對象時,該對象都被附 加上所屬的線程綁定分區(qū)的分區(qū)ID作為標簽。進一步地,線程綁定分區(qū) 在運行時可通過調(diào)用setCurrentPartition (設(shè)置當前分區(qū))方法來改變。
另外,JVMTI還可以跟蹤對象的分配,這可以通過注入字節(jié)碼實現(xiàn)。 字節(jié)碼注入可用于在字節(jié)碼中跟蹤對象分配。當對象被創(chuàng)建時調(diào)用 VMObjectAIloc事件回調(diào)函數(shù),這樣,該分配不會通過其它注入機制檢測。
此外,本領(lǐng)域的普通技術(shù)人員容易知道,除了上述的兩種實現(xiàn)堆內(nèi)存 的分區(qū)的方式之外,還可以采用其它的方式來實現(xiàn)分區(qū)。實際上,用于實 現(xiàn)堆內(nèi)存的分區(qū)的方式只要能夠?qū)崿F(xiàn)以下兩點即可(1)記錄分區(qū)與對象 之間的一對多關(guān)系;(2)獲取一個分區(qū)中的所有對象的大小并相加,從而 得到分區(qū)的大小。例如,可以使用二維表維護分區(qū)與對象之間的關(guān)系,具 體包括通過注入字節(jié)碼來截取對象的分配,然后,根據(jù)當前線程的調(diào)用 棧確定分配的對象所對應的分區(qū)并更新對應的二維表項,最后通過Java 語言提供的接口獲取對象的大小并更新對應分區(qū)的大小。
返回圖2,然后,在步驟120,檢測被劃分的各個分區(qū)的狀態(tài)以確定是 否存在某一個分區(qū)的內(nèi)存空間4皮耗盡。如上所述,可以通過檢測在某個分 區(qū)中是否出現(xiàn)內(nèi)存溢出4^ ( OutOfMemoryError)信號來確定分區(qū)的內(nèi) 存空間是否^C盡。
當存在某一個分區(qū)的內(nèi)存空間被*時,判斷為在該分區(qū)可能存在內(nèi) 存泄漏。然后,在步驟130,進一步分析該分區(qū),以獲取泄漏對象和與泄 漏對象關(guān)聯(lián)的對象。例如,可以采用現(xiàn)有工具中的LeakBot分析分區(qū)。
在本實施例中,泄漏對象是指在發(fā)生內(nèi)存泄漏時被引用的時間比所需 要的時間長的對象,與泄漏對象關(guān)聯(lián)的對象包括直接或間接引用泄漏對 象的對象和/或創(chuàng)建泄漏對象的對象。
如果不存在某一個分區(qū)的內(nèi)存空間^C^,則重復執(zhí)行步驟120。
進一步地,根據(jù)所獲取的泄漏對象和與泄漏對象關(guān)聯(lián)的對象,分析應
用程序的源代碼以獲取與內(nèi)存泄漏相關(guān)的代碼段(步驟140)。
在本實施例中,分析源代碼的方法是靜態(tài)檢查方法。具體地,根據(jù)泄 漏對象和與泄漏對象關(guān)聯(lián)的對象,跟蹤源代碼中引用這些對象的變量以標 識出潛在的泄漏引用,即,在應用程序源代碼中,找到與上述泄漏對象和 與泄漏對象關(guān)聯(lián)的對象相關(guān)的表達式(包括變量和字段),對其進行引用 計數(shù)分析,這可以通過例如固定點(Fixpoint)迭代法實現(xiàn),引用計數(shù)在 源代碼的各個程序語句中都存在的對象引起內(nèi)存泄漏的可能性更大,那么, 與這樣的對象對應的引用被標識為泄漏引用。該引用計數(shù)分析的結(jié)果可以 表明哪些對象更可能是引起內(nèi)存泄漏的源,從而縮小泄漏對象的范圍。然 后,提取所標識的潛在的泄漏引用的引用模式以確定作為內(nèi)存泄漏的源的 泄漏引用,即,對所標識的潛在的泄漏引用進行最后訪問分^f斤,以獲取這 些潛在的泄漏引用的使用情況,如果某個潛在的泄漏引用長時間沒有被使 用,則確定該泄漏引用是內(nèi)存泄漏的源。最后,跟蹤被確定為內(nèi)存泄漏的 源的泄漏引用的訪問命令,以確定添加釋放該泄漏引用的釋放語句的正確 位置,從而獲取與內(nèi)存泄漏相關(guān)的源代碼段。
此外,在獲得了與內(nèi)存泄漏相關(guān)的源代碼段之后,還可以進一步判斷 是否需要再分區(qū),例如,判斷與內(nèi)存泄漏相關(guān)的源代碼段是否太多而使得 用戶不易對源代碼段進行修復。
如果需要再分區(qū),則根據(jù)源代碼分析的結(jié)果,生成新的分區(qū)策略(步 驟150)。具體地,首先,將除了在步驟120檢測到的內(nèi)存空間WC盡的 分區(qū)以外的其它分區(qū)合并為一個分區(qū);然后,分析上述的內(nèi)存空間^W^ 的分區(qū)所對應的源代碼,根據(jù)前面描述的通過分析源代碼生成分區(qū)策略的 方法,生成上述的內(nèi)存空間被耗盡的分區(qū)的分區(qū)策略,從而獲得新的分區(qū) 策略。然后,根據(jù)新的分區(qū)策略,對Java虛擬機的堆內(nèi)存重復進行如上所 述的分區(qū)(步驟110 )、分區(qū)狀態(tài)檢測(步驟120)、分區(qū)分析(步驟130) 和源代碼分析(步驟140)。這樣,根據(jù)新的分區(qū)策略,Java虛擬機的堆 內(nèi)存可以^L進一步地分區(qū),以《更更準確地定位內(nèi)存泄漏。
此外,本領(lǐng)域的普通技術(shù)人員知道,在需要再分區(qū)時,還可以保持原
來的分區(qū)策略不變(步驟150),對在步驟120中檢測為內(nèi)存空間被^ 的分區(qū)重復進行如上所述的分區(qū)(步驟110)、分區(qū)狀態(tài)檢測(步驟120)、 分區(qū)分析(步驟130)和源代碼分析(步驟140),從而能夠更準確地定位 內(nèi)存泄漏。
如果不需要再分區(qū),則結(jié)束此次診斷內(nèi)存泄漏的過程。 通過以上描述可以看出,本實施例的基于分區(qū)的診斷Java系統(tǒng)的內(nèi)存 泄漏的方法具有以下的優(yōu)點
1. 直接而快速地診斷內(nèi)存泄漏本實施例對Java虛擬機的堆內(nèi)存進 行分區(qū),并基于這些分區(qū),通過檢測分區(qū)的內(nèi)存空間是否耗盡來檢測內(nèi)存 泄漏,因此,如果發(fā)生內(nèi)存泄漏,則可以直接而快速地檢測到。
2. 防止系統(tǒng)由于內(nèi)存泄漏而崩潰由于每個分區(qū)所有者只能將其創(chuàng) 建的對象在自己的分區(qū)范圍內(nèi)分配,因此,在某一個分區(qū)中的內(nèi)存泄漏不 會影響其它分區(qū),即使發(fā)生內(nèi)存泄漏,整個Java虛擬機也能夠保持運行。
3. 可以分析應用程序源代碼,以確定與內(nèi)存泄漏相關(guān)的源代碼段, 從而方便用戶修^Ul用程序中引起內(nèi)存泄漏的源代碼。
在同一發(fā)明構(gòu)思下,圖6是根據(jù)本發(fā)明的實施例的基于分區(qū)的診斷 Java系統(tǒng)的內(nèi)存泄漏的裝置的示意性框圖。
如圖6所示,本實施例的基于分區(qū)的診斷Java系統(tǒng)的內(nèi)存泄漏的裝置 600包括用于生成分區(qū)策略的分區(qū)策略生成器601;分區(qū)單元602,其根 據(jù)所生成的分區(qū)策略,將Java虛擬機的堆內(nèi)存劃分成多個分區(qū),其中每個 分區(qū)具有至少一個分區(qū)所有者;檢測器603,其檢測上述各個分區(qū)的狀態(tài) 以確定是否存在某一個分區(qū)的內(nèi)存空間被*;以及分區(qū)分析器604,用 于分析內(nèi)存空間被耗盡的分區(qū)以獲取泄漏對象和與泄漏對象關(guān)聯(lián)的對象。
如上所述,分區(qū)策略至少包括分區(qū)所有者和分區(qū)的大小。在本實施例 中,分區(qū)策略生成器601通過分析應用程序的源代碼來生成分區(qū)策略,其 包括對象逃逸分析器6011,用于對應用程序的源代碼執(zhí)行逃逸分析以獲 取源代碼中所有對象之間的潛在關(guān)系;距離計算單元6012,其根據(jù)對象逃 逸分析器6011的分析結(jié)果,計算每兩個對象之間的距離;聚類單元613,
其根據(jù)所計算的距離,將所有對象聚類為多個組,其中,每個組對應一個
分區(qū);以及確定單元6014,用于確定每個分區(qū)的所有者和大小。
可選地,分區(qū)策略也可以由用戶預先根據(jù)其目的生成,并直接提供給 分區(qū)單元602。在這種情況下,分區(qū)策略生成器601可以設(shè)置在基于分區(qū) 的診斷Java系統(tǒng)的內(nèi)存泄漏的裝置600的外部,其可以包括分區(qū)定義單 元,用于根據(jù)應用程序的邏輯結(jié)構(gòu)定義分區(qū),以獲得分區(qū)所有者;以及分 區(qū)大小確定單元,用于根據(jù)所獲得的分區(qū)所有者的行為,確定各個分區(qū)的 大小。
由分區(qū)策略生成器601生成的分區(qū)策略或者來自用戶的預先生成的分 區(qū)策略被提供給分區(qū)單元602,由分區(qū)單元602將Java虛擬機堆內(nèi)存劃分 為多個分區(qū)。在具體的實現(xiàn)中,如果Java虛擬機支持分區(qū)功能,則分區(qū)單 元602可以不作為單獨的單元;如果Java虛擬機不支持分區(qū)功能,則分區(qū)
單元602通過相應的接口與Java虛擬機連接,從而實現(xiàn)對堆內(nèi)存分區(qū)的功
妙 月匕-
然后,檢測器603檢測各個分區(qū)的狀態(tài),該狀態(tài)與該分區(qū)的內(nèi)存空間 的使用有關(guān)。當檢測器603檢測到某個分區(qū)出現(xiàn)OutOfMemoryError信號 時,則確定該分區(qū)的內(nèi)存空間將^L^,這表明在該分區(qū)可能發(fā)生了內(nèi)存 泄漏。
然后,分區(qū)分析器604對可能發(fā)生內(nèi)存泄漏的分區(qū)進行分析,獲取泄 漏對象和與泄漏對象關(guān)聯(lián)的對象。例如,分區(qū)分析器604可以使用現(xiàn)有工 具中的LeakBot分析分區(qū)。
進一步地,本實施例的基于分區(qū)的診斷Java系統(tǒng)的內(nèi)存泄漏的裝置 600還包括源代碼分析器605,其根據(jù)由分區(qū)分析器604獲取的泄漏對象 和與泄漏對象關(guān)聯(lián)的對象,分析應用程序的源代碼以獲取與內(nèi)存泄漏有關(guān) 的代碼段。
具體地,當所獲取的泄漏對象和與泄漏對象關(guān)聯(lián)的對象(包括類型) 作為輸入被提供給源代碼分析器605時,首先,由變量跟蹤單元6051踏J宗 源代碼中引用這些對象的變量以標識出潛在的泄漏引用,即,在應用程序
源代碼中,找到與這些泄漏對象和與泄漏對象關(guān)聯(lián)的對斜目關(guān)的表達式(包
括變量和字段),并對其進行引用計數(shù)分析,獲得與引用計數(shù)在一系列程 序命令中持續(xù)存在的對象對應的引用,并標識為潛在的泄漏引用。然后,
由提取單元6052提取所標識的潛在的泄漏引用的引用沖莫式,即,對所標識 的潛在的泄漏引用進^f亍最后訪問分析,以獲取這些潛在的泄漏引用的使用 情況,如果某個潛在的泄漏引用長時間沒有被 使用,則確定該泄漏引用是 內(nèi)存泄漏的源。然后,由源代碼修復單元6053i^^被確定為內(nèi)存泄漏的源 的泄漏引用的訪問命令,以確定添加用于釋r放該泄漏引用的釋放語句的正 確位置,從而獲取與內(nèi)存泄漏相關(guān)的源代碼段。
此外,本實施例的基于分區(qū)的診斷Java系統(tǒng)的內(nèi)存泄漏的裝置600 還可以包括判斷單元606,其根據(jù)源代碼分析器605的分析結(jié)果,判斷 是否需要再分區(qū);以及合并單元607,其將由檢測器603檢測為內(nèi)存空間 被^的分區(qū)以外的分區(qū)合并為一個分區(qū)。
當判斷單元606判斷為需要再分區(qū)時,合并單元607將除了內(nèi)存空間 被耗盡的分區(qū)以外的其它分區(qū)合并為一個分區(qū),然后,由分區(qū)策略生成器 601對內(nèi)存空間被耗盡的分區(qū)生成新的分區(qū)策略,或者保持原來的分區(qū)策 略不變,并提供給分區(qū)單元602。分區(qū)單元602利用新的分區(qū)策略或者原 來的分區(qū)策略,對Java虛擬機的堆內(nèi)存中由檢測器603檢測為內(nèi)存空間被 ^的分區(qū)進行再分區(qū)。本實施例的基于分區(qū)的診斷Java系統(tǒng)的內(nèi)存泄漏 的裝置600及其組件可以由諸如超大規(guī)模集成電路或門陣列、諸如邏輯芯 片、晶體管等的半導體、或者諸如現(xiàn)場可編程門陣列、可編程邏輯i殳備等 的可編程硬件設(shè)備的硬件電路實現(xiàn),也可以用由各種類型的處理器執(zhí)行的 軟件實現(xiàn),也可以由上述硬件電路和軟件的結(jié)合實現(xiàn)。本實施例的基于分 區(qū)的診斷Java系統(tǒng)的內(nèi)存泄漏的裝置600在^Mt上實現(xiàn)圖2所示的實施例 的基于分區(qū)的診斷Java系統(tǒng)的內(nèi)存泄漏的方法.
通過以上描述可以看出,采用本實施例的基于分區(qū)的i貪斷Java系統(tǒng)的 內(nèi)存泄漏的裝置600,由于對Java虛擬機的堆內(nèi)存進4亍分區(qū),并以分區(qū)為 單位檢測是否發(fā)生內(nèi)存^,因此,可以直接而快速地診斷出是否發(fā)生內(nèi)
存泄漏,并防止Java系統(tǒng)由于內(nèi)存泄漏而死機。而且,可以進一步分析應 用程序的源代碼以確定源代碼中與內(nèi)存泄漏相關(guān)的源代碼段,從而方便用 戶修正應用程序中引起內(nèi)存泄漏的源代碼。
雖然以上結(jié)合具體實施方式
對本發(fā)明的基于分區(qū)的診斷Java系統(tǒng)的 內(nèi)存泄漏的方法和裝置進行了詳細描述,但本發(fā)明并不限于此,在不脫離 本發(fā)明的范圍的情況下,可以對本發(fā)明進行多種變換、替換和修改。
權(quán)利要求
1.一種基于分區(qū)的診斷Java系統(tǒng)的內(nèi)存泄漏的方法,包括根據(jù)分區(qū)策略,將Java虛擬機的堆內(nèi)存劃分成多個分區(qū),其中每個分區(qū)具有至少一個分區(qū)所有者;檢測上述各個分區(qū)的狀態(tài)以確定是否存在某一個分區(qū)的內(nèi)存空間被耗盡;以及如果存在,則判斷為該分區(qū)可能存在內(nèi)存泄漏,分析該分區(qū)以獲取泄漏對象和與泄漏對象關(guān)聯(lián)的對象。
2. 根據(jù)權(quán)利要求1所述的基于分區(qū)的診斷Java系統(tǒng)的內(nèi)存泄漏的方 法,其中,所述分區(qū)策略至少包括分區(qū)所有者和分區(qū)的大小。
3. 根據(jù)權(quán)利要求1或2所述的基于分區(qū)的診斷Java系統(tǒng)的內(nèi)存泄漏 的方法,其中,所述分區(qū)策略通過以下步驟生成根據(jù)應用程序的邏輯結(jié)構(gòu)定義分區(qū),以獲得分區(qū)所有者;以及 根據(jù)所獲得的分區(qū)所有者的行為,確定各個分區(qū)的大小。
4. 根據(jù)權(quán)利要求1或2所述的基于分區(qū)的診斷Java系統(tǒng)的內(nèi)存泄漏 的方法,其中,所述分區(qū)策略通過以下的步驟生成在關(guān)系;; " _ , 、 ' , — B根據(jù)上述逃逸分析的結(jié)果,計算每兩個對象之間的距離; 根據(jù)所計算的距離,將所有對象聚類為多個組,其中,每個組對應一個分區(qū);以及確定每個分區(qū)的所有者和大小。
5. 根據(jù)權(quán)利要求1至4任意一項所述的基于分區(qū)的診斷Java系統(tǒng)的 內(nèi)存泄漏的方法,其中,所述檢測的步驟包括檢測上述各個分區(qū)是否出現(xiàn)內(nèi)存溢出^^信號;以及 如果出現(xiàn),則表明該分區(qū)的內(nèi)存空間被M。
6. 根據(jù)權(quán)利要求1至5任意一項所述的基于分區(qū)的診斷Java系統(tǒng)的 內(nèi)存泄漏的方法,還包括根據(jù)所獲取的泄漏對象和與泄漏對象關(guān)聯(lián)的對象,分析應用程序的源 代碼以獲取與內(nèi)存泄漏相關(guān)的代碼段。
7. 根據(jù)權(quán)利要求6所述的基于分區(qū)的診斷Java系統(tǒng)的內(nèi)存泄漏的方 法,其中,所述分析應用程序的源代碼的步驟包括根據(jù)所獲取的泄漏對象和與泄漏對象關(guān)聯(lián)的對象,跟蹤源代碼中引用 這些對象的變量以標識出潛在的泄漏引用;提取所標識的潛在的泄漏引用的引用模式以獲^^皮確定為內(nèi)存泄漏的 源的泄漏引用;以及跟蹤被確定為內(nèi)存泄漏的源的泄漏引用的訪問命令,以確定添加用于 釋放該泄漏引用的釋放語句的正確位置。
8. 根據(jù)權(quán)利要求6或7所述的基于分區(qū)的診斷Java系統(tǒng)的內(nèi)存泄漏 的方法,還包括根據(jù)上述分析源代碼的結(jié)果,判斷是否需要再分區(qū);如果需要再分區(qū),則生成新的分區(qū)策略或者保持原來的分區(qū)策略不變;以及利用上述新的分區(qū)策略或者上述保持不變的原來的分區(qū)策略,對上述 堆內(nèi)存或者上述檢測為內(nèi)存空間被^的分區(qū)執(zhí)行上迷分區(qū)、分區(qū)狀態(tài)檢 測、分區(qū)分析和源代碼分析的步驟。
9. 根據(jù)權(quán)利要求8所述的基于分區(qū)的診斷Java系統(tǒng)的內(nèi)存泄漏的方 法,其中,所述生成新的分區(qū)策略的步驟包括將上述檢測為內(nèi)存空間 €^的分區(qū)以外的分區(qū)合并為 一個分區(qū);以及分析上述內(nèi)存空間被耗盡的分區(qū)所對應的源代碼,以生成上述內(nèi)存空 間凈皮^的分區(qū)的分區(qū)策略。
10. —種基于分區(qū)的診斷Java系統(tǒng)的內(nèi)存泄漏的裝置,包括 分區(qū)單元,用于根據(jù)分區(qū)策略,將Java虛擬機的堆內(nèi)存劃分成多個分區(qū),其中每個分區(qū)具有至少一個分區(qū)所有者; 檢測器,用于檢測上述各個分區(qū)的狀態(tài)以確定是否存在某一個分區(qū)的內(nèi)存空間凈皮*;以及分區(qū)分析器,用于分析內(nèi)存空間被耗盡的分區(qū)以獲取泄漏對象和與泄 漏對象關(guān)聯(lián)的對象。
11. 根據(jù)權(quán)利要求10所述的基于分區(qū)的診斷Java系統(tǒng)的內(nèi)存泄漏的裝 置,還包括分區(qū)策略生成器,用于生成分區(qū)策略。
12. 根據(jù)權(quán)利要求11所述的基于分區(qū)的診斷Java系統(tǒng)的內(nèi)存泄漏的裝 置,其中,所述分區(qū)策略生成器包括分區(qū)定義單元,用于根據(jù)應用程序的邏輯結(jié)構(gòu)定義分區(qū),以獲得分區(qū) 所有者;以及分區(qū)大小確定單元,用于根據(jù)所獲得的分區(qū)所有者的行為,確定各個 分區(qū)的大小。
13. 根據(jù)權(quán)利要求11所述的基于分區(qū)的診斷Java系統(tǒng)的內(nèi)存泄漏的裝 置,其中,所述分區(qū)策略生成器包括對象逃逸分析器,用于對應用程序的源代碼執(zhí)行逃逸分析以獲取源代碼中所有對象之間的潛在關(guān)系;距離計算單元,用于根據(jù)上述逃逸分析的結(jié)果,計算每兩個對象之間的多巨離;聚類單元,用于根據(jù)所計算的距離,將所有對象聚類為多個組,其中, 每個組對應一個分區(qū);以及確定單元,用于確定每個分區(qū)的所有者和大小。
14. 根據(jù)權(quán)利要求10至13任意一項所述的基于分區(qū)的診斷Java系統(tǒng) 的內(nèi)存泄漏的裝置,其中,所述檢測器通過檢測內(nèi)存溢出4^:信號來確定 是否存在某一個分區(qū)的內(nèi)存空間#^盡。
15,根據(jù)權(quán)利要求10至14任意一項所述的基于分區(qū)的診斷Java系統(tǒng) 的內(nèi)存泄漏的裝置,還包括源代碼分析器,用于根據(jù)所獲取的泄漏對象和與泄漏對象關(guān)聯(lián)的對象, 分析應用程序的源代碼以獲取與內(nèi)存泄漏相關(guān)的代碼段。
16. 根據(jù)權(quán)利要求10至15任意一項所述的基于分區(qū)的診斷Java系統(tǒng) 的內(nèi)存泄漏的裝置,其中,所述源代碼分析器包括變量跟蹤單元,用于根據(jù)所獲取的泄漏對象和與泄漏對象關(guān)聯(lián)的對象, 跟蹤源代碼中引用這些對象的變量以標識出潛在的泄漏引用;提取單元,用于提取所標識的泄漏引用的引用模式,以獲取被確定為 內(nèi)存泄漏的源的泄漏引用;以及源代碼修復單元,用于i^J宗被確定為內(nèi)存泄漏的源的泄漏引用的訪問 命令,以確定添加用于釋放該泄漏引用的釋放語句的正確位置。
17. 根據(jù)權(quán)利要求15或16所述的基于分區(qū)的診斷Java系統(tǒng)的內(nèi)存泄 漏的裝置,還包括判斷單元,用于根據(jù)上述源代碼分析器的分析結(jié)果,判斷是否需要再 分區(qū);以及合并單元,用于在上述判斷單元的判斷結(jié)果為需要再分區(qū)時,將由上 述檢測器檢測為內(nèi)存空間祐癡f^的分區(qū)以外的分區(qū)合并為 一個分區(qū);其中,在上述判斷單元的判斷結(jié)果為需要再分區(qū)的情況下,上述分區(qū) 策略生成器對上述內(nèi)存空間凈皮耗盡的分區(qū)生成新的分區(qū)策略,或者保持原 來的分區(qū)策略不變,并提供給上述分區(qū)單元;上述分區(qū)單元利用上述新的分區(qū)策略或者上述保持不變的原來的分區(qū) 策略,對上述內(nèi)存空間^^的分區(qū)進行再分區(qū)。
全文摘要
本發(fā)明提供一種基于分區(qū)的診斷Java系統(tǒng)的內(nèi)存泄漏的方法,包括根據(jù)分區(qū)策略,將Java虛擬機的堆內(nèi)存劃分成多個分區(qū),其中每個分區(qū)具有至少一個分區(qū)所有者;檢測上述各個分區(qū)的狀態(tài)以確定是否存在某一個分區(qū)的內(nèi)存空間被耗盡;以及如果存在,則判斷為該分區(qū)可能存在內(nèi)存泄漏,分析該分區(qū)以獲取泄漏對象和與泄漏對象關(guān)聯(lián)的對象。根據(jù)本發(fā)明,Java系統(tǒng)的內(nèi)存泄漏可以被直接而快速地檢測,并且防止了系統(tǒng)由于內(nèi)存泄漏而崩潰。此外,本發(fā)明還提供了基于分區(qū)的診斷Java系統(tǒng)的內(nèi)存泄漏的裝置。
文檔編號G06F11/36GK101339533SQ20071012698
公開日2009年1月7日 申請日期2007年7月4日 優(yōu)先權(quán)日2007年7月4日
發(fā)明者劉天成, 影 李, 杰 邱, 泉 龍 申請人:國際商業(yè)機器公司