% P, e5 G9 `- `6 {2 J<TR> 4 s d }8 c2 Z3 r2 T) j<TD class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6><RE><CCID_CODE>Figure 3. Sample view of the type graph as seen in the tool</CCID_CODE></PRE></TD></TR></TABLE></CENTER>向后工作<BR><BR>自从开始我们就一直着眼于对象类,而不是单独的对象,我们不知道那个Hashtable存在泄漏。如果我们可以找出所有的Hashtable在系统中有多大,我们可以假设最大的那个Hashtable存在泄漏(因为它可以聚集足够的泄漏而变得很大)。因此,所有Hashtable,同时有和所有他们所涉及的数据,可以帮助我们查明导致泄露的精确的Hashtable。<BR><BR> 3 `, B( @+ c. O0 Z<CENTER><CCID_NOBR> 4 Z. c% |5 y% P& b) C<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=black border=1>5 Z- ?, Y, M7 D; Q& e' `6 ?2 u
4 y; _2 x' C; I+ O! }5 l<TR> . O0 [, W8 e5 ~$ V6 H8 q, J, U<TD class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6><RE><CCID_CODE>Figure 4. Screenshot of the list of 5 v/ @2 ]# W, w8 ?9 T& U& O9 u+ L# ?
Hashtable objects and the size of the data they are holding live</CCID_CODE></PRE></TD></TR></TABLE></CCID_NOBR></CENTER><BR><BR>计算一个对象所涉及的数据的开销是非常大的(这要求引用图表伴随着那个对象作为根运行)而且如果对每一个对象都这样处理,就需要很多时间。知道一些关于Hashtable内部的实现机制可以带来捷径。在内部,一个Hashtable有一个Hashtable的数组入口。数组的增长伴随着Hashtable中对象的增长。因此,要找到最大的Hashtable,我们可以把搜索限制在寻找包含Hashtable引用入口的最大的数组。这样就更快捷了。 <BR><BR>% l4 J( |* n0 P4 v) q. D
<CENTER><CCID_NOBR> 8 l0 T3 x+ h v* V. U* \) J% b8 E, @<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=black border=1>0 @0 F) }* Z1 j% N" N' f0 X& _5 H6 j
9 M8 g/ b$ a. q! s<TR> 8 v: f4 D2 m+ I" M" A- b2 X<TD class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6><RE><CCID_CODE>Figure 5. Screenshot of the listing of the . f6 y* W* J7 mlargest Hashtable entry arrays, as well as their sizes.</CCID_CODE></PRE></TD></TR></TABLE></CCID_NOBR></CENTER><BR><BR>向下深入<BR><BR>当我们发现了存在泄漏的Hashtable的实例,就可以顺藤摸瓜找到其他的引用这些Hashtable的实例,然后用上面的方法来找到是那个Hashtable存在问题。<BR><BR> ( e" A: [# t5 `- L/ m( D3 G<CENTER><CCID_NOBR>% J5 c5 ?! ^! H
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=black border=1> # U# x/ ~! E+ z P1 N" Y 3 L* C, x) O3 k+ d9 ~<TR> 4 Y6 l9 [! u* H1 _0 s$ M<TD class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6><RE><CCID_CODE>Figure 6. This is what an instance graph can look like in the tool.</CCID_CODE></PRE></TD></TR></TABLE></CCID_NOBR></CENTER><BR><BR>举个例子,一个Hashtable可以有一个来自MyServer的对象的引用,而MyServer包含一个activeSessions数据成员。这些信息就足够深入代码找出问题所在。 <BR><BR> / @8 G1 }( ?3 s5 s4 Z; d* M: Q<CENTER><CCID_NOBR> 8 D+ [3 X0 B ]<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=black border=1>9 i2 ?9 L$ z* d" S: Y: t
: D6 k$ X- {0 d# S0 G& a9 w2 N<TR> 1 C0 v5 b2 ?5 s- I6 _! I0 J<TD class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6><RE><CCID_CODE>Figure 7. Inspecting an object and its references to other objects</CCID_CODE></PRE></TD></TR></TABLE></CCID_NOBR></CENTER><BR><BR>找出分配点 <BR><BR>当发现了内存泄漏问题,找到那些泄漏的对象在何处是非常有用的。也许没有足够的信息知道他们同其他相关对象之间的联系,但是关于他们在那里被创建的信息还是很有帮助的。当然,你不会愿意创建一个工具来打印出所有分配的堆栈路径。你也不会愿意在模拟环境中运行程序只是为了捕捉到一个内存泄漏。 <BR><BR>有了JRockit Memory Leak Detector,程序代码可以动态的在内存分配出创建堆栈路径。这些堆栈路径可以在工具中累积,分析。如果你不启用这个工具,这个特征就不会有任何消耗,这就意味着时刻准备着开始。 <BR>当需要分配路径时,JRockit的编译器可以让代码不工作,而监视内存分配,但只对需要的特定类有效。更好的是,当做完数据分析后,生成的机械代码会完全被移除,不会引起任何执行上的效率衰退。<BR><BR>5 q0 N: k. [# R1 v1 d- Q1 p4 m
<CENTER>" c- `7 ~4 E( e5 y9 h
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=black border=1> / V: T" W9 T3 k! `2 _6 O1 g5 p* {/ ]" @6 y2 Z
<TR> $ W Y* K9 F+ K4 j6 R& ?<TD class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6><RE><CCID_CODE>Figure 8. The allocation stack traces for String during execution of a sample program</CCID_CODE></PRE></TD></TR></TABLE></CCID_NOBR></CENTER><BR><BR>总结 <BR><BR>内存泄漏查找起来非常困难,文章中的一些避免泄漏的好的实践,包括了要时刻记住把什么放进了数据结构中,更接近的监视内存中意外的增长。 <BR><BR>我们同时也看到了JRockit Memory Leak Detector是如何捕捉产品级系统中的内存泄漏的。该工具通过三步的方法发现泄漏。一,通过趋势分析发现那些对象类存在泄漏;二,找出同泄漏对象相关的其他类;三,向下发掘,观察独立的对象之间是如何相互联系的。同时,该工具也可以动态的,找出所有内存分配的堆栈路径。利用这三个特性,将该工具紧紧地集成在JVM中,那么就可以安全的,有效的捕捉和修复内存泄漏了。<BR><BR>8 i9 i1 Y. v! j3 j( `
<CENTER><a href="http://www.itzero.net/Article/J2EE/2005_10/3740.html" target="_blank" >上一页</A> 第 <a href="http://www.itzero.net/Article/J2EE/2005_10/3740.html" target="_blank" >1</A> <B>2</B> 页</CENTER>