简体   繁体   中英

Reference to final object in anonymous class constructor a leak?

I'm passing a runnable to a service. 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? 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.

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. So in theory, it doesn't need to have any reference to frag after creating the in-line instance.

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

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.

Having said this, it means that there are indeed instance fields (in your runnable) holding copies of all accessed variables of the outer scope. In your example, it would also have a reference to the FragMyDrive as you are simply accessing it.

All those objects become eligible for garbage collection at the same time your runnable becomes eligible for garbage collection. That means the reference to your FragMyDrive inside your runnable keeps that object alive as long as it is running.

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.

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. (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.)

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.

Hope this helps.

Interesting question. Do you have some experience in programming without automatic garbage collection, like 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.

As garbage collection works, once an object is no longer referenced, it will be subject to garbage collection and deallocated.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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