我以前在 Java 服务中使用过自定义对象,该服务始终在后端运行,有时我会收到带有跟踪的错误报告,这些跟踪显示NULL_POINTER_EXCEPTION
对象被垃圾收集器销毁。由于我拥有所有高端设备,因此无法测试静态最终对象是否被垃圾收集器销毁?
3 回答
在普通的 Java 应用程序(我不确定 Android)中,静态最终引用的对象仅在其正确的 ClassLoader 被卸载时才会被 GC。
例如,当一个容器(例如 Tomcat)中有多个 web-apps 时,取消部署每个 web-app,卸载应用程序的 ClassLoader,因此应用程序的静态最终引用的 Object 将被 GCed。但是其他 ClassLoader 加载的对象(例如其他 web-app 的 ClassLoader、common ClassLoader、boot-strap ClassLoader)不会被 GC。
所以你的问题的答案是:这取决于 ClassLoader 是否被停用。
垃圾收集器是否会删除静态最终对象?
我可以想到可能发生这种情况的三种情况:
使用 加载类的类加载器
static
变得无法访问。但这只会发生在您的代码达到没有任何东西可能注意到该对象已被 GC 处理的程度之后!某些东西使用了“讨厌的反射技巧”来分配
null
给static final
. (是的,可以做到……)有些东西正在巧妙地破坏堆;例如一些错误的 JNI / JNA 代码。
请注意,由于您(显然)正在观察对象被 GC 的影响,因此它不能是类加载器被 GC 的直接结果。必须发生其他事情才能使类加载器和final static
GC'ed 成为可能……如果这就是这里实际发生的情况。
实际上,我怀疑您的问题与 GC 无关。相反,我怀疑您的服务由于未记录的未经检查的异常而死亡。除“main”之外的线程上未捕获的异常的默认行为是默默地忽略它们。
我建议您检查您的服务线程是否正在记录所有异常,无论是catch
在run()
方法中还是在“未捕获的异常处理程序”中。
JVM 使用标记扫描 GC 算法,该算法必须检查 GC“根”位置中的所有活动引用(就像当前调用堆栈中的所有对象一样)。每个活动对象都被“标记”为活动的,并且活动对象引用的任何对象也被标记为活动的。
标记阶段完成后,GC 扫过堆,为所有未标记的对象释放内存(并为剩余的活动对象压缩内存)。
我会说“不,'final' 修饰符不会帮助 GC 减少其工作量”。