如果 activity 具有在别处引用的静态成员变量,它可以被垃圾回收吗?

Can an activity be garbage collected if it has static member variables who are referenced elsewhere?

假设一个 Activity A 有一些静态成员变量,因为静态变量是在 class 第一次被 VM 加载并停留在内存中时加载的,我想知道 Activity 会发生什么关于垃圾收集,如果其他 class B 持有 class A 的任何静态变量。? 不会收吗? 会不会被收集并初始化为初始值?

您不能引用 静态变量(或任何变量)Class。

只能保存对对象的引用,不能保存变量本身。

例如,

class MainActivity {
    public static Object obj = new Object();
}

class B {
   private Object ref = MainActivity.obj;
}

在这种情况下,只有 new Object()B 引用(因此无法进行 GC)。不是变量 obj(或 class MainActivity)本身。

Class用于示例目的

public class Activity {
    public static int primitiveStatic = 42;
    public static Object objectStatic = new Object();
}

public class B {
    public Object referenceField = null;
}

public class C {
    public int primitiveField = 0;
}

Java 对象实例的简单模型是一个内存区域,除了每个实例成员 (non-static) 的 space 外,还包含一些管理信息,包括对其 class 对象的引用。 class对象(运行时内存中的实体)包含关于class的各种信息,包括(与此问题相关的)space对于 class 的每个静态成员。请注意,其中一些依赖于 JVM。

需要注意的关键是静态成员在运行时存储在class对象中或与一起存储(不是在任何实例对象中)。

在上面的例子classes中,Activityclass对象在运行时会有两个变量,一个原始整数变量(primitiveStatic)和一个引用Object 类型 (objectStatic)。 class 的每个实例都有自己独特的内存区域,其中仅包含对 class 对象的单个引用。 B 的实例具有 space 用于单个对象引用。 C 的实例具有 space 单个原始整数值。

垃圾收集器可以移除并终结内存中任何符合收集条件的对象。这 也适用于 class 对象,但它不像实例对象那么简单,如果没有对它的引用,则该对象是合格的。 Class 对象和静态字段很少符合条件,但在卸载 class 的情况下,它们是符合条件的。有关 class 卸载的更多信息,请参阅 this documentation

我相信你想知道的案例包括这些:

案例一

new Activity();
//or
Activity a = new Activity();
a = null;

设置和分配完成后的案例 1。

加载 class,创建 class 对象和静态变量,如上所述。如上所述,创建了一个实例。该实例立即符合垃圾回收条件。收集时,实例被销毁,删除对 class 对象的引用。如果它是程序结束或在其他某些情况下,class 对象也可能被垃圾收集,删除 primitiveStaticobjectStatic 变量。在这种情况下,objectStatic 所引用的 new Object() 现在也没有对它的引用,因此可以按正常方式进行垃圾回收。

案例二

B b = new B();
b.referenceField = Activity.objectStatic;

设置和分配完成后的情况 2。

创建了一个新的 B 实例(以及 class B 的 class 对象),如上所述。加载 Activity class 并创建 class 对象(如果尚未创建)。 b 中的 referenceField 设置为引用与 objectStatic 字段相同的位置,该字段在 Activity [=156= 中或与 Activity class 对象。如果 Activity class 被卸载(在某些情况下发生但不常见),它的 class 对象将被删除,如 //1 中所述。这一次,new Object() 仍然有对它的引用,在 b.referenceField 中,因此不符合收集条件。我们剩下 B class 对象和 new Object() 以及一个实例 b,每个实例都有一个引用。

案例三

Activity a = new Activity();
B b = new B();
b.referenceField = a.objectStatic;
a = null;

设置和分配完成后的案例 3。

加载 Activity class,并创建 class 对象(如果尚未创建),如上所述。如上所述,创建了一个实例。 B class 也一样。通过找到 a 的 class 引用并将其定位在那里,静态引用 objectStatica 获得并分配给 b.referenceField。这是对引用值复制赋值,所以baActivity之间没有引用,但是b现在包含对 Activity class 构造的 new Object() 的引用。 a = null 表示 a 最初引用的 Activity 实例符合垃圾回收条件。它对 Activity class 对象的引用被删除。 Activity class 对象可能符合垃圾回收条件。如果是,则清除它包含的静态字段。 objectStatic 引用的 new Object() 现在在 b 中只有一个引用,因此不符合垃圾回收条件。我们留下了这个对象,B class 对象,以及 b 其中包含对每个对象的单个引用(与案例 //2 相同)

案例4

Activity a = new Activity();
C c = new C();
c.primitiveField = a.primitiveStatic;
a = null;

设置和分配完成后的案例 4。

//3 一样,加载 Activity class,并创建 class 对象(如果尚未创建),并创建一个实例,如所述多于。 C class 也一样。通过找到 a 的 class 引用并将其定位在那里,静态原语 primitiveStatica 获得并分配给 c.primitiveField。这只是一个复制赋值,所以caActivity之间没有引用。 a = null 表示Activity 最初由 a 引用的实例符合垃圾回收条件。它对 Activity class 对象的引用被删除。 Activity class 对象可能符合垃圾回收条件。如果是,则清除它包含的静态字段。 objectStatic 引用的 new Object() 现在没有引用,因此可以进行垃圾回收。我们剩下 C 实例 c,其 primitiveField.

中的原始 int 值为 42

在所有这些情况下,没有任何对象实例被其他引用对象的对象所阻止,这些对象也被其 class 静态字段引用(甚至 class 及其在某些情况下,静态值可以被垃圾收集),即使这些字段值是 class 的 'owned'(例如 final 并在 class 中初始化并由 class 初始化)

需要注意的是,如果objectStatic字段是final,它所指向的对象几乎永远不会被收集:Activity class必须卸下它才有资格收集。如果您有很多在程序设置后未使用的静态对象引用,这可能会成为一个问题,因为即使它们未被使用,它们也会留下并填满内存。