代码改变世界

.net垃圾回收学些【The Truth of garbage collection】【续】

2011-08-24 17:32  一一九九  阅读(203)  评论(0编辑  收藏  举报

From: http://java.sun.com/docs/books/performance/1st_edition/html/JPAppGC.fm.html#998394

Reference  Objects

      在JAVA2之前,所有的引用都是强引用。 这意味着开发人员没有任何方式和GC进行交互,除了通过像System.gc等强制方法。

         JAVA2引入了java.lang.ref Package。 图A-4显示了这个包中的类的层级结构。这个包定义了reference-object类,通过这些类可以和GC进行有限的交互。 Reference Object用来维护某个对象的引用,此时GC仍然能够回收目标对象(按理说如果某个对象被引用后,GC不能释放的)。正如你认为的, 这些额外的添加的Reference Objects和在对象生命周期中定义的Reachablility概念是统一的。理解这一点十分重要的,及时你不打算使用这些包。 有些核心类使用在内部使用 WeakReferences,所以你当你在使用Memory Profiler追踪内存的使用的时侯会遇到这些类。
       image

Resurrection(复活)

      当执行对象的finalizer方法的时候,是有可能创建一个对对象的强引用的,这种操作将对象重新放回了使用的状态。这种手法被称作复活,是个比较糟糕的注意。 Sepc保证每个对象的Finalizer方法之多运行一次。因为Finalizer方法并不会运行第二次,复活一个对象会导致比较严重的问题。

         关于更多的关于复活的信息, see ken arnold and james gosling, the Java Programming language, section 2.10.2, addison wesley, 1998.

Types  of  Reference Objects

JAVA2提供了三种类型的reference objects,  一个比后一个weaker, soft, weak, phantom. 每种类型负责不同级别的reachablility.

    • soft reference 主要为了内存敏感的cache而实现

    • weak reference 主要为了实现阻止keys或者values被释放的Mapping。

    • phontom reference are for scheduling pre-mortem cleanup actions in a more flexible way than is possible with the java finalization mechanism.

       从最强的引用到最弱的引用,不同级别reachablility反映了对象的不同的生命周期:

      • 假如一个线程不需要遍历任何引用对象就能够到达某个对象,那么这个Object是Strongly reachable.

      • 假如一个对象不是Strongly Reachable但是能够通过遍历一个Soft Reference能够到达的话,这个对象是Softly Reachable。

      • 假如一个对象即不是Strongly reachable也不是softly Reachable,但是能够通过遍历一个weak reference 到达,那么这个对象是weakly reachable。 当一个可以weakly reachable 的Object的weak references 被清除的时候,对象就进入了GC的Finalization的候选序列。

      • 假如一个对象既不是strongly, softly, weakly reachable, 而且已经被finalized了话,如果对象是phantom reachable, 此时有个phantom reference引用指向它。

      • 当一个对象在前述几种情况中都是不可reachable的话,那么对象是unreachable的,进入了GC的Finalization的候选序列。

      Example GC with WeakReference

                当使用工具查看内存泄漏的时候,你可能遇到一些特殊的reference objects. 只有strong reference会和GC直接交互。加入你发现了对象的关联串是通过Weak references来连接的,从GC的角度来说你应该能够忽略他们。

              图A-5显示了示例应用程序的对象图。这个程序的问题是Dog对象并没有被回收,这会导致一个内存泄漏。通过使用内存Profiler,你能够找到所有的指向Dog的Poionter,然后通过他们找到GC的Roots. 在图A-5中有两个GC Root, 在Class Kennel中的一个静态变量和当前线程的一个StackFrame。 在这种情况下, WagTask线程处于无限循环的状态,使得Dog对象一直处于In Use的状态。问题是怎么样能够释放Dog对象。

            这里有两个引用指向了Dog对象,但是只有其中的一个是GC关系的。 来自DogCache的WeakReference并不重要,这里值得关注的引用是来自Tail的,而tail 是来自一个Live Thread的。为了释放Dog对象和关联的Tail, 你需要终止掉是Dog处于激活状态的线程。一旦这个线程完毕了,所有的内容都会就位。 当一个被weakReference指向的对象被收集的时候, weakReference自动被设置为NULL。 图A-6显示了终止Wag线程的结果。

              image

      image

            当线程终止的时候,其堆栈也被移除了。现在只有来自Tail的强引用指向了Dog对象,这就构成了一个GC不能够Reachable的循环引用。

      Dog对象,包括tail对象,不再被任何强引用所到达。他们只有来自DogCache的一个weakly Reachable。当GC发现这个时候,GC可能会把

      weak reference 设置为NULl, 确保Dog和Tail最终是Unreachable, 成为GC的候选并且被释放掉。