首页 > 解决方案 > 一个类是否持有对其字段对象的引用?

问题描述

当涉及到实例变量,尤其是字段时,我对 GC 方面有点困惑。

因此,如果一个对象持有对其字段对象的引用,那么在对象本身存在之前,这些引用将不符合垃圾回收条件。由于线程是 GC 根,并且每个对象都必须仅在某个线程上创建,因此线程不会放弃在其上创建的任何对象,并且来自线程的整个对象层次结构将在被垃圾收集之前保留相当长的时间。

另一方面,如果一个对象放开字段对象,为这些对象调用 getter 最终会在稍后返回 null。

那么,这里的事实是什么?


澄清“字段对象”(如评论中所要求)


编辑2:更详细一点

因此,您会看到线程是通过线程对象实例在内存中表示的执行单元。任何地方发生的任何代码执行都发生在某个线程上。

这种执行将如何发生?

好吧,通过在方法中执行一些代码。是什么让这个对象被创建?

而且,这将使它成为 GC 根。

顺便说一句,对于方法调用,该特定调用有一个堆栈,这就是我在这里所指的。

标签: javagarbage-collection

解决方案


这并不像@louis-wasserman 所说的那么简单—— “是的,自然而然”,或者就此而言不是那么自然..(?)

我进行了更多调查,并在……您可能期望的地方找到了答案-Java语言规范

2.7. 对象的表示

Java 虚拟机不要求对象有任何特定的内部结构。

在 Oracle 的一些 Java 虚拟机实现中,对类实例的引用是指向句柄的指针,句柄本身就是一对指针:一个指向包含对象方法的表,另一个指向代表对象的类型,另一个是从堆中为对象数据分配的内存

是的,这就解决了。尽管 JLS 并没有强制要求 a 的内部结构java.lang.Object,但很可能会使用类似于 Oracle 的 JVM 的结构。

这具有您可能认为的更大的含义。想象一个非常的对象持有一个非常庞大的成员字段对象。嗯……Bitmap也许吧。一个 10MB 的位图和另一个对象只是保存图像的标题:

bulky_object = {位图,标题}

如果您将此对象创建为嵌套范围内的方法内的局部变量(例如,为了),则容器对象在范围结束后有资格进行垃圾收集,但如果您决定保留对位图的引用(该字段) 范围之后的对象,包含对象将不会被完全收集:

void someMethod(){
        
        // Outer block of the method
        bitmap_ref;
        
        // Nested block starts
        {
            some_object = new some_object();
            // Hold a ref to the bitmap
            bitmap_ref = some_object.bitmap;
        }
        // Nested block has ended. some_object is eligible for GC and is not accessible as a GC root
        // anymore
        
        // bitmap_ref shall remain available alive and well here as we are holding a ref to it
        // Also, some_object garbage collection may have happened leaving bitmap_ref alive
    }

这似乎是一个对象泄漏。


推荐阅读