在 Java 中释放自阻塞引用

Releasing self-blocking references in Java

这是一个相当常见的情况:classTeam 包含其所有 Member 实例的列表,而 Member 指的是其 Team。 Java 代码看起来像这样:

public class Team {
    private String name;
    private List<Member> members;

    public Team(final String name, final String... memberNames) {
        this.name = name;

        members = new LinkedList<>();
        for (String memberName : memberNames) 
            members.add(new Member(memberName, this));
    }

    public String getName() {
        return name;
    }

    @Override
    public String toString() {
        return name + ": " + members;
    }

}

class Member {
    private String name;
    private Team team;

    public Member(final String name, Team team) {
        this.name = name;
        this.team = team;
    }

    @Override
    public String toString() {
        return name + " of " + team.getName();
    }

}

再考虑一个函数 test,它创建一个 Team 实例并终止。

public static void test() {
    Team team = new Team("Family", 
        "William",  "Kate", "George");

    System.out.print(team);
}

根据常识,函数测试结束后,team对象及其所有Member实例应该被释放。但是 team 的引用计数是非零的,因为所有 Member-s 都引用它,而每个 Member 不能被释放,因为 team 持有它。

一些语言提供所谓的"weak references"(不增加引用计数,但在释放引用对象时自动设置为空)来解决这个问题,但是Java没有类似的东西那。

我可以想象一个 GC 引擎识别出 "closed" 一组相互引用但没有外部引用的对象,这样的一组对象可以被释放。但是 JVM 就一定那么聪明吗?我还没有找到任何 Java 文件来讨论这个问题,所以每次我必须创建这种结构时我都很担心。我对 Dalvik VM 特别感兴趣。

Java中的垃圾收集不是通过计算引用来工作,而是从可直接访问的对象开始:在堆栈上,在静态字段中,以及永久可访问的对象,例如类;然后它找到这些对象引用的每个对象,依此类推,并将所有引用链无法访问的对象标记为垃圾。因此,它总是会释放循环引用的垃圾,而不需要使用 WeakReference.