java - 如何在运行时查找一个对象是否引用另一个对象

标签 java garbage-collection weak-references

是否可以在运行时检查一个对象是否直接或间接引用另一个对象?

(我知道我可以使用 VisualVm 或类似工具来分析 HeapDump,但我想在运行时自动化它)

我正在使用WeakHashMap,做这样的事情:

public class MyClass {

    // the Runnable will be eventually removed if the key is collected by the GC
    private static final WeakHashMap<Object, Runnable> map = new WeakHashMap<>();

    public static void main(String[] args) {
        MyClass a = new MyClass(2);
        MyClass b = new MyClass(20);

        a = null;// no more Strong references to a
        b = null;// no more Strong references to b

        System.gc();

        for (Runnable r : map.values()) {
            r.run();
        }
        // will print (20), becouse using format() in the lambda cause a Strong
        // reference to MyClass (b) and thus the WeakHashMap will never remove b
    }

    public MyClass(int i) {

        if (i < 10) {
            map.put(this, () -> {
                System.out.println(i);
            });
        } else {
            map.put(this, () -> {
                // this is subtle, but calling format() create a strong reference 
                // between the Runnable and MyClass
                System.out.println(format(i));
            });
        }
    }

    private String format(Integer i) {
        return "(" + i + ")";
    }

}

在代码中,MyClass 的两个实例将它们自己(作为键)和一个可运行对象(作为值)添加到 WeakHashMap 中。 在第一个实例 (a) 中,Runnable 只需调用 System.out.println() 并且当实例 a 不再被引用时 (a = null)该条目将从 map 中删除。 在第二个实例 (b) 中,Runnable 还调用 MyClass 的实例函数 format()。这会创建对 b 的强引用,并将 Runnable 添加到映射中将导致锁定条件,其中该值是对键的间接强引用,防止垃圾收集器进行收集。

现在我知道要避免这些情况(例如,在 lambda 内部使用 Wea​​kreference),但是在实际场景中这很容易被忽略,并且会导致内存泄漏。

因此,在将这对添加到映射之前,我想检查该值是否以某种方式引用该键,如果是,则抛出异常。 这将是一个“调试”任务,并且将在生产中被禁用,所以我不在乎它是否缓慢或黑客攻击。

--- 更新 ---

我正在尝试处理WeakListeners,并避免它们在没有引用的情况下被立即收集。 所以我将它们注册为 notifier.addWeakListener(holder, e -> { ... }); 这会将监听器添加到 WeakHashMap 中,防止在持有者存活之前收集监听器。 但是监听器中对持有者的任何引用都会创建一个锁:(

有更好的方法吗?

最佳答案

Reflection API使您可以访问运行时对象的所有字段(及其运行时类型,可能还包括 Class 对象)。理论上,您可以遍历实例的字段(以及类上的静态字段)、字段的字段等的树。

虽然这是可能的,但我怀疑它是否可行。您写道您不关心性能,但对于开发运行来说甚至可能太慢。这就引出了实现您自己的缓存的规则 1:不要这样做。

关于java - 如何在运行时查找一个对象是否引用另一个对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52445894/

相关文章:

java - Spring Social Facebook 登录的工作示例,github 上的示例应用程序除外

memory-management - 将引用转换回闭包内的强引用,内存管理,swift

c# - 从 ConditionalWeakTable<T> 获取事件项列表

java - Android 暂停和恢复教程

java - 老年代对象的统计?

c++ - 如何 GC(删除)GetOpenFileName 的线程

java - JVM - WeakReferences 是否在次要 GC 中收集?

java - LDAP 搜索过滤器表达式实用程序或库

java - 通过扩展具体的 parent 来拥有抽象的 child 的目的

java - 对打印方法进行单元测试