3

我读到Java 是按值传递的。所以假设我们有这个代码,并说它的HashMap somehashMap生命周期比foo. 所以 foo 不允许被垃圾回收,即使它已经完成了它的工作,只是因为我们把 foo 放在 Map 中然后忘记从中删除。现在按照我链接到的帖子中答案的逻辑,我们实际上是在传递foo对方法的引用的副本,put()对吗?在这种情况下,将其foo放入HashMap不应阻止它被垃圾收集。你能帮我理解这里发生了什么吗?我到底错过了什么?

 public void someMethod(){
     Foo foo  = new Foo();
     somehashMap.put(fooKey,foo); 
  }
4

9 回答 9

11

垃圾收集不适用于引用,但适用于驻留在堆中的实际对象。当你把foo.MapsomehashMap

Java 中的引用在幕后透明地处理。当您将引用放入映射时,引用foo的副本实际上被传递给方法调用,但底层对象即原始引用和复制引用是相同的。让我们看看下面的代码片段:putnew Foo()

public void doIt() {
  Object f1 = new Object();
  Object f2 = f1;
  Object f3 = f2;
}

在上面的代码片段中,执行完成后有多少对象被垃圾回收doIt?这只是new Object()我们创建的单曲。其余都是简单的引用或别名,用于指向同一个对象。

于 2012-07-31T13:26:37.577 回答
7

只要对象是可访问的,它就不能被垃圾收集。在您的情况下, foo 可以通过Foo foo = someHashMap.get(fooKey);所以不能被垃圾收集,只要它在地图中并且地图本身是可以访问的。

于 2012-07-31T13:27:26.327 回答
6

我认为您不清楚参考实际上是什么。

'foo' 是对对象的引用,你说得对,将其添加到 hashmap 会有效地创建对同一对象的第二个引用。

然而,这正是为什么当你的 'foo' 变量消失时对象不会被垃圾回收的原因。仅当没有引用时才会对对象进行垃圾收集 - 您从一个引用 (foo) 开始,然后创建第二个引用(在 hashmap 内),第一个引用在函数结束时消失,但您仍然有一个引用。

于 2012-07-31T13:28:18.263 回答
6

试一张图:

在此处输入图像描述

盒子是对象。未装箱的字母是变量。

一开始你只有你的哈希图,我假设它在你的函数被调用之前就存在,然后继续存在。

然后new Foo()创建一个新对象,并f=创建一个引用它的变量。

然后hashmap.put(k,f)在 hashmap 中创建一个条目,它指向与 f 相同的对象。

然后,当您退出该函数时,局部变量f将不复存在,但其他所有内容都将保留。

垃圾收集器不会删除 Foo 对象,因为 hashmap 仍然指向它。这就是你想要的——如果你以后调用hashmap.get(k),你会期望得到那个 Foo 对象。

如果您从 hashmap 中删除该条目 -hashmap.remove(k)那么 Foo 对象可以被垃圾收集。

如果 hashmap 本身不再存在,则可以对 Foo 对象进行垃圾收集。

于 2012-07-31T13:51:44.210 回答
3

大多数带有垃圾收集器的语言都支持某些类型的弱引用。例如,您可以在 Java 中找到一个弱哈希映射实现。如果将 foo 对象放入弱哈希映射并且垃圾收集器将运行,那么如果不存在指向 foo 的其他指针(周指针除外),则 foo 对象将被收集并从弱哈希映射中删除。有时您可以通过这种方式避免内存泄漏。

于 2012-07-31T13:27:18.413 回答
2

只要 foo 在 HashMap 中,它就不能被垃圾收集,因为 Java 不知道你永远不会再使用它。foo 可以在所有引用结束后立即被垃圾回收。

于 2012-07-31T13:28:02.893 回答
2

我们实际上是将 foo 引用的副本传递给 put() 方法,对吗?

的,Java 正在将实习映射持有的引用的副本传递referencesame object内存中 ( heap),因此在您的映射之前它没有资格进行 GC。

于 2012-07-31T13:28:20.413 回答
1

在这种put方法的情况下,按值传递是对 的引用的值foo。既然foo是引用计数,只要somehashMap持有引用,foo就不会被垃圾回收。

我确实在一些我继承的代码中发现了这样的内存泄漏,其中有人使用地图缓存图像,但是当再次需要图像时,不是抓取缓存的图像,而是创建了一个新的图像并将其推入地图一把新钥匙。

于 2012-07-31T13:27:34.503 回答
1

Java 确实是按值传递的。但是,您是按值传递引用,而不是对象的实例

于 2012-07-31T13:28:25.173 回答