我正在将runnable传递给服务。可运行的持续时间可能比通过它的片段/活动寿命更长。我想知道以下代码片段是否会通过在runnable中维护引用来泄漏frag对象?我意识到我可以在runnable之外移动包含frag的整行(就像我用“String key = frag ...”所做的那样),但我只是想要了解匿名类如何/何时泄漏对象
我真的不确定。 runnable只需要frag来在初始化实例时确定变量,并在此处进行内联初始化。因此从理论上讲,在创建内联实例后,不需要对frag进行任何引用。
如果我在run()函数中有一个对frag的引用,我认为会保证泄漏,因为它需要保持frag活着以便在将来某个时候引用它(而且frag很可能是gc' d在那一点上,但作为参考)。
private static void fg_downloadFile(final FragMyDrive frag, final File file, final Drive drive){
final String key = frag.getCastedActivity().getKey();
Runnable rx_downloadFile = new Runnable() {
Context ServiceContext = frag.getCastedActivity().mService;
@Override
public void run() {
bg_downloadFile(ServiceContext, key, file, drive);
}
};
//.... Submit runnable to service...
}
答案 0 :(得分:2)
正如您所知,您必须在外部声明变量 final ,但在匿名类中使用它们。这里的Java技巧是将所有这些变量复制到该匿名类的隐式生成的实例字段中。
话虽如此,但这意味着确实存在实例字段(在您的runnable中),其中包含外部作用域的所有访问变量的副本。在您的示例中,当您只是访问它时,它也会引用FragMyDrive
。
在runnable有资格进行垃圾回收的同时,所有这些对象都有资格进行垃圾回收。这意味着只要它正在运行,对runnable中FragMyDrive
的引用就会使该对象保持活动状态。
将这些引用缩小到您真正需要的范围始终是一个好主意:
private static void fg_downloadFile(final FragMyDrive frag, final File file, final Drive drive){
final String key = frag.getCastedActivity().getKey();
final Context context = frag.getCastedActivity().mService;
Runnable rx_downloadFile = new Runnable() {
@Override
public void run() {
bg_downloadFile(context, key, file, drive);
}
};
//.... Submit runnable to service...
}
这里唯一(隐式生成的)实例字段是:
String key
Context context
File file
Drive drive
答案 1 :(得分:1)
我不确定我是否理解您正确使用内联这个词,但无论如何,我都不认为这里有任何泄露。
Var final String key
只是静态函数fg_downloadFile()
中的本地引用,因此在函数末尾超出范围时会释放它。
只要Runnable
线程存在,frag
匿名内部类仍然可以保持引用(再次,不是Runnable
而是其中的某个子属性)。 (更确切地说,编译器实际上使用构造函数和implementation
成员变量生成Runnable
final
个成员变量,将任何隐式使用的引用复制到fg_downloadFile()
&#39中可用的任何内容;范围。)
但无论如何,一旦所有代码都被执行,所有对frag
的(子成员)的引用都将被删除,垃圾收集器可以拾取垃圾。
希望这有帮助。
答案 2 :(得分:0)
有趣的问题。你有没有自动垃圾收集的编程经验,比如Objective C?
但是要回答你的问题,我不明白为什么会出现泄漏。 我想会发生的事情是Runnable会保留对frag的引用以供它自己使用,但是在将来的某个时候,一旦服务不再需要它,frag也会被垃圾收集,因此它不会引用它
当垃圾收集工作时,一旦不再引用对象,它将被垃圾收集和解除分配。