首页 > 解决方案 > 将非静态变量更改为静态变量

问题描述

我正在阅读有关 GC 的内容,并了解到当一个对象有资格进行垃圾收集时,GC 必须在其finalize上运行该方法。该finalize方法保证只运行一次,因此 GC 将对象标记为已完成并让它休息直到下一个循环。

在 finalize 方法中,您可以从技术上“复活”一个对象,例如,通过将其分配给静态字段。该对象将再次变得活跃并且不符合垃圾回收条件,因此 GC 不会在下一个周期收集它。

但是,该对象将被标记为已完成,因此当它再次符合条件时,将不会调用 finalize 方法。本质上,您只能在对象的生命周期内将这个“复活”技巧转动一次。

我觉得这很有趣。但是,如果我的变量是非静态的,如何将其更改为finalize方法内的静态?

记住:

如果无法从任何活动线程或任何静态引用访问对象,则该对象符合垃圾收集或 GC 的条件。因此,hack 是将对象添加到finalize方法内的静态资源中,这样只会阻止一次垃圾收集。该finalize方法受到保护,因此可以被子类覆盖,无论它们是否在同一个包中。

这是一种危险的做法,无需使用内部应用程序代码。

标签: javagarbage-collectionjvmmetaspace

解决方案


在运行时更改变量定义并不容易,在某些情况下几乎是不可能的。可能有一些讨厌的反射技巧可能涉及内联编译、类加载等,但你不应该这样做。将变量从静态更改为非静态或反之亦然也将涉及在存储中移动数据并处理潜在的冲突 - 所以不要这样做。

无论如何,变量只是引用,要复活一个对象,您只需要从活动线程创建一个新引用。这可以通过一些由静态变量引用并且this引用被添加到的集合来完成。

示例(仅用于说明目的,除非您真的知道自己在做什么并且有充分的理由这样做,否则不要使用它):

class NastyResurrector {
  public static Collection<Object> RESURRECTED_OBJECTS = ...;// use whatever collection implementation you like
}

然后finalize()你会打电话NastyResurrector.RESURRECTED_OBJECTS.add(this),你有你的参考。

但是,我将引用您问题的来源(问题 Q11):

请注意,只有在您真正知道自己在做什么时才应该使用这种丑陋的技巧

这是我认为最重要的收获。


推荐阅读