HashMap.remove和垃圾回收

3
如果我将对象添加到HashMap中,然后在不再需要它们时只调用remove方法,是否保证它们占用的资源会被释放(假设没有其他引用指向它们)?

1
HashMaps不会存储对象,它们可以存储引用。 - user253751
1
дҢ еЏҮд»ӨдҢүз”Ё WeakHashMap ж›үд»Ә HashMapгЂ‚ - Prashant
如果您从Map中删除了任何对象的过时引用,则它将无法进行垃圾回收。在删除之前,您需要显式将其设置为null。 - Prashant
2
@Prashant 我猜他想知道在 map.put("key", new SomeClass());map.remove("key") 之后,SomeClass 的对象是否有资格被垃圾收集器删除。 - SubOptimal
6个回答

4
如果您确定:
没有其他对它们的引用
是的,它们是GC的候选项,但这并不意味着它们会立即被收集!!
您可以使用:
System.gc();

但这不是一个好主意。欲了解更多信息,请查看thisthis的问题。


嗨@olegst,如果这个或任何答案解决了您的问题,请考虑通过点击勾号接受它。这将向更广泛的社区表明您已找到解决方案,并为回答者和您自己赢得一些声望。这并没有义务去做。 - Jordi Castilla

2

HashMap的条目存储在数组中。如果您删除一个条目,则相关的数组位置将变为null。因此,hashMap不再引用已删除的value对象。

然后,垃圾回收的普通规则将应用于value对象。

验证的简单代码。

public class REPL7 {

    public static void main(String[] args) throws Exception {
        Map<String, Foo> map = new HashMap();
        map.put("one", new Foo("foo one"));
        map.put("two", new Foo("foo two"));

        // make the backing array accessible
        Field field = map.getClass().getDeclaredField("table");
        field.setAccessible(true);
        Object[] obj = (Object[]) field.get(map);

        // two references to Foo objects will be shown            
        System.out.println("obj = " + Arrays.toString(obj));

        map.remove("one");

        // only one reference to a Foo object will eb shown
        System.out.println("obj = " + Arrays.toString(obj));
    }
}

class Foo {
    String marker;

    Foo(String marker) {
        this.marker = marker;
    }

    @Override
    public String toString() {
        return "Foo{" + marker + '}';
    }
}

1
不行,因为你可能在其他地方引用了该对象。
简单的例子:
Map < int, Object > map = new HashMap < int, Object > ();
CustomObject x = new CustomObject();
map.put(1, x);
map.remove(1);
//you still have access to x

他的意思是... map.put(x); x = null; map.remove(x); - Jordi Castilla
@JordiCastilla 当x==null时,map.remove(x)将无法按预期工作。 - ivan.mylyanyk
2
@GoogleHireMe 他的意思是 map.put(key, x); x=null; map.remove(key); - olegst

1
垃圾回收总是在堆内存中进行,所有对象都会被初始化。 当您在HashMap中调用remove方法时,它只会删除其ID和值,而不是您创建的对象。

0
如果Map是唯一引用该对象的东西,并且您从Map中删除了对该对象的引用,则该对象将不再被任何地方引用,因此将有资格进行垃圾回收。与往常一样,它所占用的资源肯定会被释放,但不能保证何时会发生这种情况。

-1

我将对象放入HashMap中,然后将它们移除。

放置在HashMap中的对象的类:

public class ObjectTestsub {

    String name;
    
    public ObjectTestsub(String name) {
        this.name = name;
    }

    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        System.out.println("ObjectTestsub: " + name + " is garbage collected");
    }
}

主函数:

public class ObjectTest {

    HashMap<String, ObjectTestsub> map;

    public static void main(String[] args) {

        var map = new HashMap<String, ObjectTestsub>();

        for (int i = 0; i < 1000000; i++) {
            map.put("Obj" + i, new ObjectTestsub("first " + i));
            map.remove("Obj" + i);
        }
    }
}

输出:

....
ObjectTestsub: first 822685 is garbage collected
ObjectTestsub: first 822684 is garbage collected
ObjectTestsub: first 822683 is garbage collected
ObjectTestsub: first 822682 is garbage collected
....
ObjectTestsub: first 822677 is garbage collected
ObjectTestsub: first 822676 is garbage collected
ObjectTestsub: first 822675 is garbage collected
ObjectTestsub: first 822674 is garbage collected

"被销毁"的对象数量是Java垃圾回收器考虑的因素。 这里重要的是一些对象被回收(因此已被释放)。 一切都进行得很好。

现在我改变了代码:

public class ObjectTest {

    HashMap<String, ObjectTestsub> map;

    public static void main(String[] args) {

        var map = new HashMap<String, ObjectTestsub>();

        for (int i = 0; i < 1000000; i++) {
            map.put("Obj" + i, new ObjectTestsub("first " + i));
        }
        System.out.println("first part has DONE!       size: " + map.size());
        
        for (int i = 0; i < 1000000; i++) {
            map.remove("Obj" + i);
        }
        System.out.println("second part has DONE!       size: " + map.size());
    }
}

这里是输出:

first part has DONE!       size: 1000000
second part has DONE!       size: 0

"ObjectTestsub"对象的“析构函数”不再有任何消息。 看起来它们还没有被释放...

问题出在哪里? :/


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接