检索实例的 ID,就像 Eclipse 的调试器一样

问题描述 投票:0回答:2

当您在调试器中暂停时,Eclipse 有一个方便的功能,可以显示每个实例的 ID。它们看起来是连续的并且基于分配实例的时间:

当我深入研究一个实质性问题时,我发现这些非常有用,因为它们通常是小整数,比完整的哈希码或其他一些内部 ID 更容易记住。他们会非常快速地检查“这仍然是我认为的那个物体吗?”当您单步执行复杂而深入的调用堆栈时。

这些分配 ID 是由 jvm 本身跟踪的,还是 Eclipse 通过某种未知机制提供的?

有什么方法可以从代码中获取它们,以便我可以在调试时临时将它们放入日志消息中?

我真的不想为每个对象添加 ID 字段,有很多充分的理由说明这是一个坏主意。

java eclipse debugging jvm
2个回答
4
投票

这些分配 ID 是由 jvm 本身跟踪的,还是 Eclipse 通过某种未知机制提供的东西?

对象 ID 由 JDWP 代理生成。 JDWP 代理是一个通过 JDWP 协议向外部 Java 调试器(如 Eclipse IDE)公开 JVM 调试功能的库。

代理通常通过命令行选项

-agentlib:jdwp=
-Xrunjdwp
与 JVM 一起启动。

它们似乎是连续的并且基于实例的时间 已分配

当代理需要向调试器发送对象引用时,会按需生成 ID。它们与对象创建时间之类的无关。 Java 对象最初没有分配 ID。

有什么方法可以从代码中获取它们

正如我上面所说,在代理与调试器交换对象引用之前,对象 ID 并不存在。

但是您可以使用

IdentityHashMap
或类似工具为对象生成自己的 ID。以下是创建此类 ID 的最简单方法:

private static final Map<Object, Long> map = new IdentityHashMap<>();

private static long nextId;

public static long getId(Object o) {
    synchronized (map) {
        Long id = map.get(o);
        if (id == null) {
            map.put(o, id = ++nextId);
        }
        return id;
    }
}

当然,这个实现并不完美,因为它使用全局锁并永久存储对象。更好的解决方案是一种 WeakIdentityConcurrentMap

事实上,这正是 JDWP 代理生成对象 ID 的方式。它保留一个内部哈希表,将对象映射到顺序递增的整数,并使用引用计数进行删除。请参阅 commonRef.c


0
投票

作为我在构造函数中使用的唯一 ID

id = System.nanoTime() % 1000;

© www.soinside.com 2019 - 2024. All rights reserved.