0

I wrote a Parcelable class and out of curiosity I wrote some debug output whenever it is created and whenever the finalize() method is called. The Parcable is put as Extra into an Intent that is used to start an Activity.

Now I see the following: Whenever I launch the Activity, my Parcelable is instantiated once (by my code), then internally parceled once and instantiated via parceling twice and afterwards finalize() is only called for two of the three created Parcelable instances (and the two finalize calls happen immediately after the Activity has launched).

So on every Activity launch, the Parcelable is instantiated three times, but only two instances are freed.

I thought maybe the third one is collected at some time later by the Garbage Collector, but I forced garbage collecting through the Android Profiler many times and used the app intensively, but the my Parcelables are never deallocated. So I have one leaking Parcable per Activity launch.

Is there something I can do about that? Has anyone seen a similar behaviour? Is this a bug in Android?

Here's the stripped down code of my Parcable:

public class MyParcelable implements Parcelable {

    private final static String TAG = "MyParcelable";

    public MyParcelable() {
        Log.d(TAG, "MyParcelable()");
    }

    @Override
    protected void finalize() throws Throwable {
        Log.d(TAG, "finalize()");
        super.finalize();
    }

    // Parcelable:

    protected MyParcelable(Parcel in) {
        Log.d(TAG, "MyParcelable(parcel)");
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        Log.d(TAG, "writeToParcel()");
    }

    public static final Creator<MyParcelable> CREATOR = new Creator<MyParcelable>() {
        @Override
        public MyParcelable createFromParcel(Parcel in) {
            return new MyParcelable(in);
        }

        @Override
        public MyParcelable[] newArray(int size) {
            return new MyParcelable[size];
        }
    };

    @Override
    public int describeContents() {
        return 0;
    }
}

The output is something like that:

MyParcelable()
writeToParcel()
MyParcelable(parcel)
MyParcelable(parcel)
finalize()
finalize()
Mani
  • 51
  • 4
  • How are you referencing the Parcelable instances? Potentially the one in the current activity's Intent Bundle isn't getting GCed. – Submersed Mar 02 '18 at 18:53
  • Some people at least seem to think that finalize() is not guaranteed to be called, e.g. [this post](https://stackoverflow.com/questions/31183341/how-to-address-the-do-not-override-the-object-finalize-method-issue). So if you want to find out whether there's a memory leak you'd better use some other tool - take a look at [Memory Profiler](https://developer.android.com/studio/profile/memory-profiler.html) and count your MyParcelable instances – Bö macht Blau Mar 02 '18 at 19:04
  • I know I should not rely on finalize(). I have some external resources for that I do some reference counting and that has to be freed once all Parcable instances are gone. So in addition to the finalize() code I added a close() method to my Parcelable. Bad thing: The leaking Parcelable is NOT the first one that I instantiate myself in my code. It's one of the two that Android is unparceling while starting the Activity. I have no chance to call close() on that internal copy. :-( – Mani Mar 02 '18 at 20:06

0 Answers0