有没有办法在不引用对象的情况下接收对象?

Is there a way to receive object, without having reference to it?

假设如下代码:

Object obj = new Object();
obj = null;

此时,我没有对该对象的任何引用,但它仍在堆中,因为垃圾收集不会立即发生。有没有办法在 GC 收集之前重新获取对该对象的引用?

目前我看到的唯一可能的方法是使用 Unsafe,它提供直接内存访问,但我需要知道对象在内存中的确切分配位置。还有,还有Weak\SoftReference,不过是通过特殊的GC行为实现的。

P.S。预测像 "Why do you need it?" 这样的问题 - 因为科学不是关于为什么,而是关于为什么不! (c)

At this point, i don't have any reference to this object, but it's still on the heap, because garbage collection don't happens instantly.

它在哪里是未定义的,垃圾回收是否立即发生也是未定义的。

Is there a way to re obtain reference on this object, before it'll be collected by GC?

你已经有了一个,但你把它扔掉了。留着吧。

I will need to know where in memory exactly object is allocated.

标准 Java 中没有任何内容可以告诉您这一点,如果您可以获得这些信息,也没有任何有用的方法可以利用这些信息。

Also, there is Weak/SoftReference, but they are implemented by special GC behavior.

我不明白这对你的问题有什么影响,不管它是什么。

这是高度特定于 JVM 实现的。在具有与每个对象关联的内存分配信息的天真的实现中,您可能会找到一个内存尚未被释放的对象,并且您似乎正在考虑这个方向。

然而,复杂的 JVM 不是这样工作的。将分配信息与每个对象相关联会产生巨大的开销,因为您可能 运行 时间内有数百万个对象。不仅涉及内存需求,还涉及在分配或释放对象时为维护这些信息而必须完成的工作量。

那么是什么让堆内存的一部分成为对象呢?只有您持有的参考资料。垃圾收集器遍历现有的引用并在以这种方式找到的对象中,它会找到元信息(即指向 class 特定信息的指针),以了解有多少内存属于该对象以及如何解释包含的数据(遍历子引用,如果有的话)。一切未被引用的东西本身都是未使用的,可能包含旧对象或者可能根本就没有被使用过,谁知道呢。一旦对一个对象的所有引用都消失了,就没有关于这个对象以前存在的信息了。

言归正传,没有明确的释放动作。当垃圾收集器找到 surviving 个对象时,它们将被复制到一个专用的新位置,而它们的旧位置被认为是空闲的,无论之前有多少个对象和多少内存每个单独的对象在存在时都被占用。

当你搜索被认为是未使用的内存时,你可能会找到旧对象的回忆,但如果不参考它们的起点,就不可能说看起来像对象的位模式是否真的是死对象或者只是巧合。即使你设法以这种方式复活了一个对象,它与你最初想要复活一个引用的想法无关,因为 gc 还没有运行。

请注意,对这个普通生命周期的所有修改都是通过持有对该对象的另一个引用来工作的。例如,当 class 定义了一个重要的 finalize() 方法时,JVM 必须添加对需要终结的对象队列的引用。同样,soft、weak 和 phantom references 封装了对相关对象的引用。调试器也可以保留对对象的引用,一旦它看到它。

但是对于您的普通代码 Object obj = new Object(); obj = null;,假设中间没有设置断点,则不会有额外的引用,因此无法恢复对象。在 运行 时间优化代码时,JVM 甚至可以省略整个分配。因此,当搜索对象时,您甚至不会在 RAM 中找到该对象的剩余部分,因为该对象实际上从未存在过。