当实际对象被垃圾回收时,WeakHashMap条目中的值如何被垃圾回收? [英] How does a value in an entry in the WeakHashMap gets garbage collected when the actual object is garbage collected?

查看:158
本文介绍了当实际对象被垃圾回收时,WeakHashMap条目中的值如何被垃圾回收?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

首先,我想澄清我对WeakReference的理解,因为以下问题是相同的.

First of all I would like to clarify my understanding of the WeakReference as the following question depends on the same.

static void test() {
    Person p = new Person();
    WeakReference<Person> person = new WeakReference<>(p);
    p = null;
    System.gc();
    System.out.println(person.get());
    System.out.println(person);
}

static class Person {
    String name;
}

static class PersonMetadata {
    String someData;

    public PersonMetadata(String met) {
        someData = met;
    }
}

以上代码的输出为

null java.lang.ref.WeakReference@7852e922

null java.lang.ref.WeakReference@7852e922

这意味着,尽管有一个实际的人对象在GC运行后就被垃圾回收了,但内存中仍然有一个WeakReference<Person>类的对象,此时该对象没有指向任何对象.

Which means that although there is the actual person object is garbage collected once a GC runs, there is an object of WeakReference<Person> class is there in the memory which does not point to anything at this point.

现在考虑到上述理解为真,我对WeakHashMap<K,V>的工作方式感到困惑.在下面的代码中

Now considering the above understanding true, I am confused about how does WeakHashMap<K,V> works. In the below code

public static void main(String[] args) {
    Person p = new Person();
    p.name = "John";
    WeakHashMap<Person, PersonMetadata> map = new WeakHashMap<>();
    PersonMetadata meta = new PersonMetadata("Geek");
    map.put(p, meta);
    p = null;
    System.gc();
    if (map.values().contains(meta)) {
        System.out.println("Value present");
    } else {
        System.out.println("Value gone");
    }
}

static class Person {
    String name;
}

static class PersonMetadata {
    String someData;

    public PersonMetadata(String met) {
        someData = met;
    }
}

输出: Value gone

现在,问题是因为据说WeakHashMap<K,V>中的键是一个弱引用,这意味着在上面的代码中,当 p 变为null实际对象可以被垃圾回收,因为不再有对该对象的更强引用,但是作为PersonMetadata类的对象的值和值如何被垃圾回收作为第一个对象代码证明WeakReference类的对象即使实际对象被收集也不会被垃圾收集.

Now the the question is as it is said that the key in WeakHashMap<K,V> is an weak reference which means that in the above code when p becomes null the actual object can be garbage collected as there is no more strong reference to the object, but how does the and the value which is an object of PersonMetadata class is getting garbage collected as the first code proves that object of WeakReference class is not garbage collected even though the actual object is collected.

推荐答案

您误会了这种情况.当map.values().contains(meta)或简称map.containsValue(meta)返回false时,并不表示meta已被垃圾回收.实际上,您在meta中持有对该对象的引用,甚至将该引用传递给可能在其上调用equalscontains方法.那么该对象如何被垃圾回收?

You are misunderstanding the situation. When map.values().contains(meta), or short map.containsValue(meta) returns false, it doesn’t imply that meta has been garbage collected. In fact, you are holding a reference to the object in meta and even passing that reference to the contains method which may invoke equals on it. So how could that object be garbage collected?

响应仅告诉您地图的一个键与该对象没有关联,并且由于唯一的键已被垃圾回收,因此这是正确的答案.另外,您可能只是要求map.isEmpty()检查该关联是否存在.

The response only tells you that there is no association from one of the map’s keys to that object and since the only key has been garbage collected, that’s the correct answer. Alternatively, you could just have asked map.isEmpty() to check for the presence of the association.

这是 WeakHashMap 提供:

This is what the WeakHashMap provides:

Map接口的基于哈希表的实现,带有弱键.如果WeakHashMap中的条目不再是普通使用的键,它将被自动删除.更准确地说,给定键的映射的存在不会阻止该键被垃圾收集器丢弃,即被终结化,终结和回收.丢弃键后,其条目会从映射中有效删除,因此此类的行为与其他Map实现有所不同.

Hash table based implementation of the Map interface, with weak keys. An entry in a WeakHashMap will automatically be removed when its key is no longer in ordinary use. More precisely, the presence of a mapping for a given key will not prevent the key from being discarded by the garbage collector, that is, made finalizable, finalized, and then reclaimed. When a key has been discarded its entry is effectively removed from the map, so this class behaves somewhat differently from other Map implementations.

该条目的删除不是瞬时的.它依赖于将WeakReference排队到ReferenceQueue中,然后在进行下一个查询(例如containsValue甚至是size())时在内部对其进行轮询.例如.如果我将您的程序更改为:

The removal of the entry is not instantaneous. It relies on enqueuing of the WeakReference into a ReferenceQueue, which is then polled internally when you make the next query, like containsValue or even size(). E.g. if I change your program to:

Person p = new Person();
WeakHashMap<Person, PersonMetadata> map = new WeakHashMap<>();
PersonMetadata meta = new PersonMetadata("Geek");
map.put(p, meta);
WeakReference<?> ref = new WeakReference<>(p);
p = null;
while(ref.get() != null) System.gc();
System.out.println(map.containsValue(meta)? "Value present": "Value gone");

尽管此时已证明关键Person实例已被垃圾回收,但它偶尔还是打印"Value present".如上所述,这是关于地图的内部清理,而不是我们一直在meta中拥有很强参考力的PersonMetadata实例.

It occasionally prints "Value present" despite the key Person instance provenly has been garbage collected at this point. As said above, this is about the map’s internal cleanup, not about the PersonMetadata instance to which we’re holding a strong reference in meta anyway.

使PersonMetadata符合垃圾回收的条件是完全不同的.如前所述,每当我们调用一个方法it时,WeakReference都会进行内部清理.如果我们不这样做,就不会进行清理,因此,即使密钥已被垃圾回收,它仍然是一个很好的参考.考虑:

Making PersonMetadata eligible to garbage collection is an entirely different thing. As said, the WeakReference does an internal cleanup whenever we call a method an it. If we don’t, there will be no cleanup and hence, still a strong reference, even if the key has been garbage collected. Consider:

Person p = new Person();
WeakHashMap<Person, PersonMetadata> map = new WeakHashMap<>();
PersonMetadata meta = new PersonMetadata("Geek");
map.put(p, meta);
WeakReference<?> personRef = new WeakReference<>(p);
WeakReference<?> metaRef = new WeakReference<>(meta);
p = null;
meta = null;
while(personRef.get() != null) System.gc();
System.out.println("Person collected");
for(int i = 0; metaRef.get() != null && i < 10; i++) {
    System.out.println("PersonMetadata not collected");
    System.gc();
    Thread.sleep(1000);
}
System.out.println("calling a query method on map");
System.out.println("map.size() == "+map.size());
System.gc();
System.out.println("PersonMetadata "+(metaRef.get()==null? "collected": "not collected"));

将打印哪个

Person collected
PersonMetadata not collected
PersonMetadata not collected
PersonMetadata not collected
PersonMetadata not collected
PersonMetadata not collected
PersonMetadata not collected
PersonMetadata not collected
PersonMetadata not collected
PersonMetadata not collected
PersonMetadata not collected
calling a query method on map
map.size() == 0
PersonMetadata collected

演示WeakHashMap如何强烈引用已经收集的键的值,直到我们最终对其调用一个方法,以使它有机会执行其内部清理.

demonstrating how the WeakHashMap holds a strong reference to the value of an already collected key until we eventually invoke a method on it, to give it a chance to perform its internal cleanup.

WeakHashMap或我们的方法都没有引用时,才最终收集该值.当我们删除meta = null;语句时,地图的末尾(内部清理后)仍将为空,但不会收集该值.

The value finally gets collected when neither, the WeakHashMap nor our method, hold a reference on it. When we remove the meta = null; statement, the map still will be empty at the end (after its internal cleanup), but the value won’t be collected.

请务必牢记,这些代码示例仅用于演示目的和特定于实现的行为,尤其是main方法通常未优化运行.从形式上讲,如果未使用该引用对象,则不需要局部变量来防止垃圾收集,这在优化方法时在实践中具有重要意义.

It’s important to keep in mind that these code examples are for demonstration purposes and touch implementation specific behavior, most notably, that a main method usually runs unoptimized. Formally, local variables are not required to prevent garbage collection if the referent is otherwise unused, a point which has relevance in practice when methods have been optimized.

这篇关于当实际对象被垃圾回收时,WeakHashMap条目中的值如何被垃圾回收?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆