垃圾收集在内部地图中跟踪自己实例的对象

时间:2008-12-06 20:55:50

标签: java garbage-collection map object

在我的类的构造函数中,我将当前对象( this )及其键(在构造函数中作为参数输入的字符串)映射到静态LinkedHashMap中,以便我可以引用字符串的对象我以后可能需要它。

这是代码(如果它有帮助):

public class DataEntry {
    /** Internal global list of DataEntry objects. */
    private static LinkedHashMap _INTERNAL_LIST;

    /** The data entry's name. */
    private String NAME;

    /** The value this data entry represents. */
    private Object VALUE;


    /** Defines a DataEntry object with a name and a value. */
    public DataEntry( String name, Object value )
    {
        if( _INTERNAL_LIST == null )
        {
            _INTERNAL_LIST = new LinkedHashMap();
        }

        _INTERNAL_LIST.put( name, this );

        NAME = name;
        VALUE = value;
    }
}

问题?当我使用它们时,这个类的实例不会被垃圾收集。

我只是好奇是否有办法让这个类的实例在我完成使用它们时自行清理而不必每次都手动调用Remove()方法或其他东西(在内部删除它的引用) LinkedHashMap,当我不再使用它们时,我的意思是。)

3 个答案:

答案 0 :(得分:6)

改为使用值WeakReferences(或SoftReferences)。这样,值仍然可以被垃圾收集。当然,你仍然会在地图中有条目 - 但是你可以定期清除Weak / SoftReference现在为空的任何条目的地图。

答案 1 :(得分:5)

在构造函数完成之前使对象可见,这不是线程安全的。

目前尚不清楚地图在这种情况下是如何使用的,但是假设在类中有这样的静态方法:

public static DataEntry getEntry(String name) {
  return _INTERNAL_LIST.get(name);
}

另一个并发运行的线程可以在创建时访问DataEntry,并开始使用未初始化VALUE的条目。即使您对构造函数中的代码重新排序,以便将新实例添加到地图是您做的最后一件事,JVM也可以重新排序指令,以便首先将对象添加到列表中。或者,如果类被扩展,子类初始化可以在对象发布后进行。

如果多个线程访问与DataEntry类的交互,则可能会出现并发错误,该错误与平台有关,间歇性且非常难以诊断。

Brian Goetz的文章"Safe Construction,"提供了有关此主题的更多信息。

回到原来的问题:正如其他人所提到的那样,使用WeakReference是一种很好的方法,但我不建议迭代地图中的每个条目,而是建议为你的值创建一个包装器{ {1}}(可能是您的WeakReference本身或帮助者),并在ReferenceQueue中对每个引用进行排队。这样,您可以快速轮询队列以查找任何收集的条目,并将其从地图中删除。这可以通过在类初始化程序中启动的后台线程(在remove上阻塞)来完成,或者每次添加新条目时都可以清除任何过时的条目(polling)。

如果您的程序是多线程的,则应放弃DataEntry以获取java.util.concurrent的地图,或将LinkedHashMap包裹在Collections.synchronizedMap()

答案 2 :(得分:1)

您想要使用的内容似乎是一个弱参考。这个概念是弱引用不足以强迫对象不被GC化。我对他们没有多少经验,但你可以了解更多here