是否可以在运行时检查一个对象是否直接或间接引用另一个对象?
(我知道我可以使用 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 内部使用 Weakreference),但是在实际场景中这很容易被忽略,并且会导致内存泄漏。
因此,在将这对添加到映射之前,我想检查该值是否以某种方式引用该键,如果是,则抛出异常。 这将是一个“调试”任务,并且将在生产中被禁用,所以我不在乎它是否缓慢或黑客攻击。
--- 更新 ---
我正在尝试处理WeakListeners,并避免它们在没有引用的情况下被立即收集。
所以我将它们注册为 notifier.addWeakListener(holder, e -> { ... });
这会将监听器添加到 WeakHashMap 中,防止在持有者存活之前收集监听器。
但是监听器中对持有者的任何引用都会创建一个锁:(
有更好的方法吗?
最佳答案
Reflection API使您可以访问运行时对象的所有字段(及其运行时类型,可能还包括 Class
对象)。理论上,您可以遍历实例的字段(以及类上的静态字段)、字段的字段等的树。
虽然这是可能的,但我怀疑它是否可行。您写道您不关心性能,但对于开发运行来说甚至可能太慢。这就引出了实现您自己的缓存的规则 1:不要这样做。
关于java - 如何在运行时查找一个对象是否引用另一个对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52445894/