【问题标题】:any way to tell if a method ended or local in method in no longer in use?有什么方法可以判断方法是否结束或方法中的本地不再使用?
【发布时间】:2018-08-26 13:59:59
【问题描述】:

在这种情况下,我需要一些解决方案来帮助我了解一些方法:

void myMethod(...)
{
    MyObject obj = new MyObject();
    // do stuff
}

如果此方法已结束或 obj 不可达(这将表明该方法已结束)。

我正在编写一个小型 java 代理,我希望有一些技术可以让我确定此方法已结束或 obj 无法访问...在我的情况下,“do stuff”部分不使用对象。它不会将此变量传递到其他地方或将其添加到某个集合中。

我知道通过 Weak/Soft/Phantom-References 我可以部分实现这一点。如果调用了 GC,则通过:

void myMethod(...)
{
    MyObject obj = new MyObject();
    WeakReference objReference = new WeakReference(obj);

    // do stuff
}

我总是可以在不同的地方验证:

    if (objReference.get() == null) ...

但是,这只有在发生 GC 时才可能成立。

有没有其他方法可以实现这一目标? 例如,一些标记 JVM 可能会放在这个变量上,因为很明显这是一个绝对可以被垃圾回收的局部变量......

我不想依赖 ASM - 并为所有这些方法添加一个 try-finally 包装器。希望有一个更微妙、基于参考的解决方案。

【问题讨论】:

  • 在定义局部变量后将其放入堆栈/队列中,在方法的最后拉取它。您可能依赖方法的结果(将其存储在某处),如果它存在,很明显它的所有局部变量都不是“活动的”。不过,我不明白这样做的目的。
  • 方法的结尾不是微不足道的——它可能是 if/else 分支中的一堆返回,或者如果该方法抛出并捕获了异常,那也将终止该方法的执行

标签: java weak-references soft-references phantom-reference


【解决方案1】:

我能想到的唯一可靠方法......就是使用回调/监听器;例如

public MyClass

    void myMethod(Function<MyClass, Void> onCompletion) {
        try {
            // Do stuff
        } finally {
            onCompletion.apply(this);
        }
    }

您也可以使用MethodHandles.tryFinally 来实现这一点,为您的方法创建方法句柄,通过包装方法来实现回调。

任何基于Reference 类型的东西都隐含地依赖于垃圾回收。这会很昂贵,而且您几乎无法控制何时收到通知。


有没有其他方法可以实现这一目标?例如,一些标记 JVM 可能会放在这个变量上,因为很明显这是一个绝对可以被垃圾回收的局部变量......

AFAIK,不,没有。并且 JVM / JIT 并没有按照您的假设进行;即,它们不会在正常 GC 周期之前标记一个“明显的”本地来完成或收集。

他们为什么不呢?因为如果发生这种情况,它会使应用程序变慢。唯一的好处是最终确定/引用处理可能会更快发生,但对于编写良好的应用程序来说没有任何区别。编写良好的程序不应该关心何时完成/参考处理发生,因为规范明确不保证时间。

事实证明,逃逸分析也无济于事:

现在我知道 JIT 可能会调整告诉 GC 仍在范围内的内容的表(请参阅 @Holger 的评论;例如 finalize() called on strongly reachable object in Java 8)。但这不会改变方法的指令顺序。只有 GC 会关注这些信息……在 GC 运行时

【讨论】:

  • 谢谢,但我明确写了“我不想依赖 ASM - 并为所有这些方法添加一个 try-finally 包装器”
  • 我知道你做到了。不幸的是,这是你唯一的选择,AFAIK。
  • 为什么需要基于参考的解决方案。答案是通知该方法已结束的最佳(实际上是最佳)方式之一。
  • 实际上,JVM 代码转换,它结合了局部变量的实际使用并允许更早地收集对象,这些对象会天真地被认为是由局部变量引用的。正如“finalize() called on strongly reachable object in Java 8”所展示的,这甚至可能适用于this。但是,它仍然需要实际的垃圾回收才能使对象被回收。而且,有趣的是,它歪曲了 OP 的实际意图:对象的集合并不能证明方法已经完成。
猜你喜欢
  • 2014-04-18
  • 1970-01-01
  • 2012-05-30
  • 2012-09-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-22
  • 2011-02-03
相关资源
最近更新 更多