自从开始我们就一直着眼于对象类,而不是单独的对象,我们不知道那个 Hashtable存在泄漏。如果我们可以找出所有的Hashtable在系统中有多大,我们可以假设最大的那个Hashtable存在泄漏(因为它可以聚集足够的泄漏而变得很大)。因此,所有Hashtable,同时有和所有他们所涉及的数据,可以帮助我们查明导致泄露的精确的Hashtable。

Figure 4. Screenshot of the list of Hashtable objects and the size of the data they are holding live

Figure 5. Screenshot of the listing of the largest Hashtable entry arrays, as well as their sizes.
当我们发现了存在泄漏的Hashtable的实例,就可以顺藤摸瓜找到其他的引用这些Hashtable的实例,然后用上面的方法来找到是那个Hashtable存在问题。

Figure 6. This is what an instance graph can look like in the tool.

Figure 7. Inspecting an object and its references to other objects
当发现了内存泄漏问题,找到那些泄漏的对象在何处是非常有用的。也许没有足够的信息知道他们同其他相关对象之间的联系,但是关于他们在那里被创建的信息还是很有帮助的。当然,你不会愿意创建一个工具来打印出所有分配的堆栈路径。你也不会愿意在模拟环境中运行程序只是为了捕捉到一个内存泄漏。
有了JRockit Memory Leak Detector,程序代码可以动态的在内存分配出创建堆栈路径。这些堆栈路径可以在工具中累积,分析。如果你不启用这个工具,这个特征就不会有任何消耗,这就意味着时刻准备着开始。当需要分配路径时,JRockit的编译器可以让代码不工作,而监视内存分配,但只对需要的特定类有效。更好的是,当做完数据分析后,生成的机械代码会完全被移除,不会引起任何执行上的效率衰退。

Figure 8. The allocation stack traces for String during execution of a sample program
内存泄漏查找起来非常困难,文章中的一些避免泄漏的好的实践,包括了要时刻记住把什么放进了数据结构中,更接近的监视内存中意外的增长。
我们同时也看到了JRockit Memory Leak Detector是如何捕捉产品级系统中的内存泄漏的。该工具通过三步的方法发现泄漏。一,通过趋势分析发现那些对象类存在泄漏;二,找出同泄漏对象相关的其他类;三,向下发掘,观察独立的对象之间是如何相互联系的。同时,该工具也可以动态的,找出所有内存分配的堆栈路径。利用这三个特性,将该工具紧紧地集成在JVM中,那么就可以安全的,有效的捕捉和修复内存泄漏了。
