当前位置: 首页 > 知识库问答 >
问题:

对象何时有资格进行垃圾收集?

巫马淳
2023-03-14

在下面的代码中,假设调用了amethodmyObject最初引用的对象在哪一点/哪一行符合垃圾收集的条件?

class Test {
  private Object classObject;

  public void amethod() {
    Object myObject = new Object();
    classObject = myObject;
    myObject = null;
  }
}

如果class Objectamethod有一个公共、受保护、默认或静态的访问修饰符,它会影响对象在什么点上有资格进行垃圾收集吗?如果是,它会受到什么影响?

  • 我的第一个想法是,当测试对象有资格进行垃圾收集时,该对象有资格进行垃圾收集

共有3个答案

井浩思
2023-03-14

Java语言规范实际上精确地解决了这一问题,

优化程序的转换可以被设计成减少可访问对象的数量,使其少于那些天真地认为可访问的对象。例如,Java编译器或代码生成器可以选择设置一个不再用于null的变量或参数,以使此类对象的存储可以更快地回收。

如果对象字段中的值存储在寄存器中,则会出现这种情况的另一个例子。然后,程序可能会访问寄存器而不是对象,并且不再访问对象。这意味着该对象是垃圾…

但是

…请注意,只有当引用位于堆栈上,而不是存储在堆中时,才允许进行这种优化。

例如,考虑终结器守护模式:

   class Foo {
       private final Object finalizerGuardian = new Object() {
           protected void finalize() throws Throwable {
               /* finalize outer Foo object */
           }
       }
   } 

终结器守护者强制super。finalize在子类重写finalize且未显式调用super时调用。完成

如果允许对存储在堆上的引用进行这些优化,那么Java编译器可以检测到,finalizerGuardian字段从未被读取,将其清空,立即收集对象,并尽早调用终结器。这与意图背道而驰:当Foo实例变得不可访问时,程序员可能想要调用Foo终结器。因此,这种转换是不合法的:只要外部类对象是可访问的,内部类对象就应该是可访问的。

这个例子可以1:1应用到你的例子中,只要对象被实例字段classObject引用,它就不能在包含引用的Test实例之前得到垃圾收集。

然而,请注意,当使用Test实例应用于代码时,规范中提到的积极优化仍然是允许的。只要同时收集Test实例和引用对象,就可能发生比预期更早的收集。在这种情况下,§12.6中规定的以下方面适用:

Java编程语言没有对finalize方法调用进行排序。终结器可以按任何顺序调用,甚至可以同时调用。

因此,Test实例很可能比classObject引用的对象更早被收集,而“内部”对象的终结器则更早被调用。唯一可以保证的是,当内部对象的终结器运行时,外部对象是不可访问的(或者具有挂起或并发终结)。因为在你的例子中,两个都没有一个非平凡的终结器,这并不重要…

桂丰
2023-03-14

摘自OCA Java SE 7书

当对象无法再被访问时,会将其标记为有资格被垃圾收集,当对象超出范围时,就会发生这种情况。当对象的引用变量被指定一个显式空值或被重新初始化时,也会发生这种情况。

班宏毅
2023-03-14

在丢弃对该对象的所有引用之前,该对象不会成为垃圾收集的候选对象。Java对象是通过引用分配的,所以

   classObject = myObject;

您为堆上的同一对象分配了另一个引用。所以这条线

   myObject = null;

只删除一个引用。要使myObject成为垃圾收集的候选对象,您必须

  classObject = null;
 类似资料:
  • 根据这个问题的答案,在第11行没有符合GC条件的对象;但是根据我的说法,至少有一个对象t2,它在第6行被设置为指向null,应该有资格进行垃圾回收。

  • 在执行之后,我很难理解。有多少对象有资格进行垃圾收集?

  • 有人能给我解释一下原因吗?

  • 我有一个Web应用程序,它生成了大量后台工作线程,以响应对某个endpoint的请求。为了提高工作人员状态的透明度,我添加了一个事件总线,工作人员可以将事件发布到该总线。事件被推送到地图中,跟踪每个工作人员随时间的状态。地图定期被快照并推送到更永久的位置,在那里快照通过请求令牌与请求相关联。 为每个请求提供自己的事件总线当然很有吸引力。然后每个请求得到它自己的映射。当请求完成并推送最终快照时,映射

  • 问题内容: 我有一段代码可以在内存中加载很大的图像。所以打电话似乎是合理的事情 在加载图像之前。据我所知,它毫无问题。 昨天,我决定使用一个名为FindBugs的非常有用的软件来扫描您的代码并报告可能导致错误或通常不建议使用的策略的问题。问题是我提到的这段代码得到了报告。描述是这样的: …强迫垃圾收集;除了基准测试代码外,都非常可疑 并继续阐述: 代码显式调用垃圾回收。除了基准测试中的特定用途外,

  • [GC(分配失败)[defnew:10931K->472K(12288K),0.0053905秒]10931K->10712K(39616K),0.0054285秒][times:user=0.00 sys=0.00,real=0.01秒] [GC(分配失败)[defnew:10712k->472k(12288k),0.0057686秒]20952k->20952k(39616k),0.00580