Main Activity is not garbage collected after destruction because it is referenced by InputMethodManager indirectly

安稳与你 提交于 2019-11-26 19:28:51

问题


I followed "Avoiding Memory Leaks" article from here.

However the proposed solution does not solve the leak problem. I tested this with android emulator on Windows XP (SDK 2.3.1). I dumped the heap and checked the main activity is still in the heap (I used MAT)

Here's what I did:

  1. create HelloWorld app with HelloWorldActivity (it has no child views)
  2. run Emulator and launch HelloWorld app.
  3. close it by clicking back-key.
  4. Cause gc in DDMS and dump heap <-- Here I found HelloWorldActivity instance.
  5. 'Path to GC Roots' from it shows the following path.

HelloWorldActivity <- PhoneWindow$DecorView <- InputMethodManager

InputMethodManager is a singleton and three references to DecorView which references HelloWorldActivity.

I can't understand why InputMethodManager still references DecorView instance even after the activity is destroyed.

Is there any way to make sure that the main activity is destroyed and GC-able after closing it?


回答1:


It seems that calling InputMethodManager's methods 'windowDismissed' and 'startGettingWindowFocus' do the stuff.

Something like this:

@Override
protected void onDestroy()
{
    super.onDestroy();
    //fix for memory leak: http://code.google.com/p/android/issues/detail?id=34731
    fixInputMethodManager();
}

private void fixInputMethodManager()
{
    final Object imm = getSystemService(Context.INPUT_METHOD_SERVICE);

    final Reflector.TypedObject windowToken
        = new Reflector.TypedObject(getWindow().getDecorView().getWindowToken(), IBinder.class);

    Reflector.invokeMethodExceptionSafe(imm, "windowDismissed", windowToken);

    final Reflector.TypedObject view
        = new Reflector.TypedObject(null, View.class);

    Reflector.invokeMethodExceptionSafe(imm, "startGettingWindowFocus", view);
}

Reflector's code:

public static final class TypedObject
{
    private final Object object;
    private final Class type;

    public TypedObject(final Object object, final Class type)
    {
    this.object = object;
    this.type = type;
    }

    Object getObject()
    {
        return object;
    }

    Class getType()
    {
        return type;
    }
}

public static void invokeMethodExceptionSafe(final Object methodOwner, final String method, final TypedObject... arguments)
{
    if (null == methodOwner)
    {
        return;
    }

    try
    {
        final Class<?>[] types = null == arguments ? new Class[0] : new Class[arguments.length];
        final Object[] objects = null == arguments ? new Object[0] : new Object[arguments.length];

        if (null != arguments)
        {
            for (int i = 0, limit = types.length; i < limit; i++)
            {
                types[i] = arguments[i].getType();
                objects[i] = arguments[i].getObject();
            }
        }

        final Method declaredMethod = methodOwner.getClass().getDeclaredMethod(method, types);

        declaredMethod.setAccessible(true);
        declaredMethod.invoke(methodOwner, objects);
    }
    catch (final Throwable ignored)
    {
    }
}



回答2:


If I understand your question correctly, the answer is: no, you cannot make sure the activity is gc'ed. Your activity's onDestroy() method should have been called and the activity shut down. That does not mean, however, that the process is killed or that the activity is gc'ed; that's managed by the system.




回答3:


I have noticed that some listeners tend to keep a reference to the activity under some circumstances, even after the activity supposedly has been finished. A rotation from portrait to landscape can, for example, restart your activity and if you're unfortunate your first activity is not gc-ed properly (in my case due to some listeners still holding a reference to it).

Being a former C/C++ programmer I have it implanted in my spine to "un-set" any listeners in Activity.onDestroy() (setXyzListener(null)).

EDIT:

Just as Ted commented below, one should indeed "set" and "un-set" listeners in Activity.onResume() and Activity.onPause() respectively.



来源:https://stackoverflow.com/questions/5038158/main-activity-is-not-garbage-collected-after-destruction-because-it-is-reference

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!