简体   繁体   English

在匿名类构造函数中引用最终对象是否泄漏?

[英]Reference to final object in anonymous class constructor a leak?

I'm passing a runnable to a service. 我正在将一个runnable传递给一个服务。 The runnable duration may outlive the fragment / activity that passes it. 可运行的持续时间可能比通过它的片段/活动寿命更长。 I'm wondering if the following code snippet would leak the frag object by maintaining a reference inside the runnable? 我想知道以下代码片段是否会通过在runnable中维护引用来泄漏frag对象? I realize I can move the whole line containing frag outside of the runnable (like I did with "String key = frag..."), but I'm asking simply to get an understanding of how/when an anonymous class would leak an object. 我意识到我可以在runnable之外移动包含frag的整行(就像我用“String key = frag ...”所做的那样),但我只是想要了解匿名类如何/何时泄漏宾语。

I'm really not certain. 我真的不确定。 The runnable only needs frag to determine a variable upon initializing the instance, and it's initialized in-line here. runnable只需要frag来在初始化实例时确定变量,并在此处进行内联初始化。 So in theory, it doesn't need to have any reference to frag after creating the in-line instance. 因此从理论上讲,在创建内联实例后,不需要对frag进行任何引用。

If I had a reference to frag in the run() function, I would think a leak then would be guaranteed as it would need to keep frag alive to reference it sometime in the future (and frag might very well be gc'd at that point, but for the reference). 如果我在run()函数中有一个对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...
}

As you might know, you must make variables final when declaring them outside but using them in an anonymous class. 您可能知道,在向外声明变量时必须使变量成为最终变量,但在匿名类中使用它们。 The Java trick here is to copy all those variables into implicitly generated instance fields of that anonymous class. 这里的Java技巧是所有这些变量复制到该匿名类的隐式生成的实例字段中。

Having said this, it means that there are indeed instance fields (in your runnable) holding copies of all accessed variables of the outer scope. 话虽如此,但这意味着确实存在实例字段(在您的runnable中),其中包含外部作用域的所有访问变量的副本。 In your example, it would also have a reference to the FragMyDrive as you are simply accessing it. 在您的示例中,它也会引用FragMyDrive因为您只是访问它。

All those objects become eligible for garbage collection at the same time your runnable becomes eligible for garbage collection. 在您的runnable有资格进行垃圾回收的同时,所有这些对象都有资格进行垃圾回收。 That means the reference to your FragMyDrive inside your runnable keeps that object alive as long as it is running. 这意味着在runnable中对FragMyDrive的引用会使该对象保持活动状态,只要它正在运行。

It's always a good idea to narrow down those references to what you really need: 将这些引用缩小到您真正需要的范围始终是一个好主意:

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...
}

Here the only (implicitly generated) instance fields are: 这里唯一(隐式生成的)实例字段是:

String key
Context context
File file
Drive drive

I'm not sure I understand your use of the word inline correctly but in any case, I don't think anything is leaked here. 我不确定我是否理解你对内联词的正确使用,但无论如何,我认为这里没有任何泄漏。

Var final String key is simply a local reference in your static function fg_downloadFile() so it's freed when going out of scope at the end of the function. Var final String key只是静态函数fg_downloadFile()的本地引用,因此在函数fg_downloadFile()超出范围时会释放它。

The Runnable anonymous inner class may still hold a reference (again, not to frag but to some sub-property therein) for as long as the Runnable thread lives. 只要Runnable线程存在, Runnable匿名内部类仍然可以保持引用(再次,不是对于frag而是对其中的某些子属性)。 (More precisely, the compiler actually generates an implementation of Runnable with a constructor and final member variables that copy any implicitly used references to whatever is available in fg_downloadFile() 's scope.) (更确切地说,编译器实际上使用构造函数和final成员变量生成Runnableimplementation ,该变量将任何隐式使用的引用复制到fg_downloadFile()范围内可用的任何引用。)

But in any case, once the all code has been executed, all references to (sub-members of) frag will be removed and the garbage collector can pick up the trash. 但无论如何,一旦所有代码都被执行,所有对frag (子成员)的引用都将被删除,垃圾收集器可以拾取垃圾。

Hope this helps. 希望这可以帮助。

Interesting question. 有趣的问题。 Do you have some experience in programming without automatic garbage collection, like Objective C? 你有没有自动垃圾收集的编程经验,比如Objective C?

But to answer your question, I don't see why it would be a leak. 但是要回答你的问题,我不明白为什么会出现泄漏。 What I suppose will happen is that the Runnable will keep a reference to frag for it's own use, but at some point in the future, frag will get garbage collected as well once the service does not need it anymore, and hence it's not refering to it. 我想会发生的事情是Runnable将保留对frag的引用以供它自己使用,但是在将来的某个时候,一旦服务不再需要它,frag也会被垃圾收集,因此它不会引用它。

As garbage collection works, once an object is no longer referenced, it will be subject to garbage collection and deallocated. 当垃圾收集工作时,一旦不再引用对象,它将受到垃圾收集和解除分配。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM