EditText causing memory leak
Asked Answered
N

2

16

Intro:

I have an app which has the following structure: ActionBar up top (ActionBarSherlock) ViewPagerIndicator below that (for tabs) ViewPager (hosts Fragments)

I have a problem that one of my fragments is causing a rather major memory leak. I narrowed the problem down to the following case:

The fragment which is causing the leak does nothing but inflating a layout in it's onCreateView method. This is done the following way:

return inflater.inflate(R.layout.filter_auctions_fragment, container, false);

Nothing unusual here.

The layout file only includes a ScrollView, LinearLayout and two EditTexts in it (includes more normally stuff but i narrowed the problem down to just these views to make it simple).

Now the code that's used to add the fragment: mTabsAdapter.addTab(tabName, ProblematicFragment.class);

mTabsAdapter is an instance of TabsAdapter, a class that extends FragmentPagerAdapter of the support library. It's rather standard so I'm not including the source to keep this question as short as possible.

Now the funny part:

This is what happens with the heap when i rotate my device back and forth a few times:

12-28 12:26:27.180: D/dalvikvm(18841): GC_CONCURRENT freed 530K, 7% free 10701K/11436K, paused 4ms+7ms, total 58ms
12-28 12:26:27.180: D/dalvikvm(18841): WAIT_FOR_CONCURRENT_GC blocked 24ms
12-28 12:26:28.270: D/dalvikvm(18841): GC_CONCURRENT freed 737K, 8% free 11048K/11964K, paused 4ms+5ms, total 53ms
12-28 12:26:29.510: D/dalvikvm(18841): GC_CONCURRENT freed 789K, 8% free 11464K/12436K, paused 5ms+5ms, total 42ms
12-28 12:26:30.640: D/dalvikvm(18841): GC_CONCURRENT freed 888K, 9% free 11919K/12984K, paused 4ms+5ms, total 52ms
12-28 12:26:31.810: D/dalvikvm(18841): GC_CONCURRENT freed 903K, 8% free 12421K/13500K, paused 3ms+8ms, total 58ms
12-28 12:26:33.800: D/dalvikvm(18841): GC_CONCURRENT freed 1092K, 9% free 13005K/14272K, paused 4ms+6ms, total 59ms
12-28 12:26:33.800: D/dalvikvm(18841): WAIT_FOR_CONCURRENT_GC blocked 20ms
12-28 12:26:36.000: D/dalvikvm(18841): GC_CONCURRENT freed 1355K, 11% free 13518K/15048K, paused 3ms+8ms, total 74ms
12-28 12:26:36.000: D/dalvikvm(18841): WAIT_FOR_CONCURRENT_GC blocked 19ms
12-28 12:26:38.110: D/dalvikvm(18841): GC_CONCURRENT freed 1450K, 11% free 14106K/15720K, paused 3ms+11ms, total 72ms
12-28 12:26:40.450: D/dalvikvm(18841): GC_CONCURRENT freed 1530K, 11% free 14807K/16516K, paused 2ms+15ms, total 75ms
12-28 12:26:40.450: D/dalvikvm(18841): WAIT_FOR_CONCURRENT_GC blocked 29ms
12-28 12:26:43.030: D/dalvikvm(18841): GC_CONCURRENT freed 1682K, 11% free 15591K/17452K, paused 3ms+10ms, total 66ms
12-28 12:26:43.030: D/dalvikvm(18841): WAIT_FOR_CONCURRENT_GC blocked 32ms

Clearly, a memory leak. Yes, i know it causes the Activity to be recreated from the ground up and this is what I want because i have different layouts for landscape and portrait modes. Nontheless it shouldn't cause a memory leak.

I've found the source of this problem. It's the two EditText's that i mentioned earlier. As soon as i remove them from the layout and do the same test (rotate back and forth). These are the GC messages i get:

12-28 12:21:41.270: D/dalvikvm(17934): GC_CONCURRENT freed 534K, 7% free 10853K/11576K, paused 3ms+7ms, total 44ms
12-28 12:21:42.560: D/dalvikvm(17934): GC_CONCURRENT freed 818K, 9% free 11113K/12108K, paused 11ms+9ms, total 95ms
12-28 12:21:44.680: D/dalvikvm(17934): GC_CONCURRENT freed 1036K, 10% free 11313K/12528K, paused 3ms+6ms, total 54ms
12-28 12:21:44.680: D/dalvikvm(17934): WAIT_FOR_CONCURRENT_GC blocked 15ms
12-28 12:21:47.420: D/dalvikvm(17934): GC_CONCURRENT freed 1089K, 10% free 11510K/12780K, paused 2ms+6ms, total 79ms
12-28 12:21:47.420: D/dalvikvm(17934): WAIT_FOR_CONCURRENT_GC blocked 39ms
12-28 12:21:50.200: D/dalvikvm(17934): GC_CONCURRENT freed 1317K, 12% free 11461K/12956K, paused 4ms+13ms, total 84ms
12-28 12:21:53.210: D/dalvikvm(17934): GC_CONCURRENT freed 1629K, 14% free 11148K/12956K, paused 3ms+7ms, total 47ms
12-28 12:21:55.580: D/dalvikvm(17934): GC_CONCURRENT freed 1056K, 13% free 11302K/12956K, paused 4ms+7ms, total 59ms
12-28 12:21:57.280: D/dalvikvm(17934): GC_CONCURRENT freed 1306K, 14% free 11200K/12956K, paused 5ms+5ms, total 82ms
12-28 12:21:59.420: D/dalvikvm(17934): GC_CONCURRENT freed 1035K, 12% free 11408K/12956K, paused 3ms+7ms, total 55ms
12-28 12:22:01.990: D/dalvikvm(17934): GC_CONCURRENT freed 1392K, 13% free 11352K/12956K, paused 4ms+9ms, total 54ms
12-28 12:22:01.990: D/dalvikvm(17934): WAIT_FOR_CONCURRENT_GC blocked 30ms

Now that's what I want to see!

WHY!?

Can someone tell my why this is happening? I would like to add that I'm not keeping a reference to these EditText object anywhere in my app (I normally do, but even when i removed all of them for testing purposes the leak still happens).

Bonus - MAT Screenshots of the leak:

Path to GC Roots (whtout soft/weak refs) for my Activity

Path to GC Roots (whtout soft/weak refs) for my "ProblematicFragment"

As you can see there are 16 instances of the Fragment AND the Activity, while there should be only one.

EDIT:

I noticed that when i manually add the fragment in a different activity (using FragmentManager.beginTransaction()) the leak does not occur!!! I'm completely confused now...

EDIT2:

Removing the android:id attribute of the EditTexts fixes it... But now they're pretty useless...

Nairn answered 28/12, 2012 at 12:21 Comment(6)
You did not fold open the originalText portion of the MAT display to see where your extra copies are coming from. See the third line from the bottom of your screenshots.Ornithine
Maybe this SO discussion is related - #8498465Saguaro
I have the same issue, have you found a solution?Sylvie
Did you test on devices with api > 11Tetrastich
Are you passing either of the EditText's or the Activity to a method or constructor from another class?Rondeau
clearly the edittext is leaking the context with all the objects in it. possibly caused by the container param in your inflate callAlcoran
A
9

I have found a solution that fits my needs.

I tracked the problem down to widget.EditableInputConnection. Which I think does the lookup in the suggestion system. It is also responsible for holding on to my Activity, hence causing a memory leak.

I do not need the suggestions so I wanted to turn it off. However it has proven to be difficult. EditText.setInputType did not work, neither in xml nor code.

I ended up doing the following. The magic is happening in onCreateInputConnection():

public class MyEditText extends TextView {
    public MyEditText(Context context) {
        this(context, null);
    }

    public MyEditText(Context context, AttributeSet attrs) {
        this(context, attrs, android.R.attr.editTextStyle);
    }

    public MyEditText(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
        return null;
    }

    @Override
    protected boolean getDefaultEditable() {
        return true;
    }

    @Override
    protected MovementMethod getDefaultMovementMethod() {
        return ArrowKeyMovementMethod.getInstance();
    }

    @Override
    public Editable getText() {
        return (Editable) super.getText();
    }

    @Override
    public void setText(CharSequence text, BufferType type) {
        super.setText(text, BufferType.EDITABLE);
    }

    /**
     * Convenience for {@link Selection#setSelection(Spannable, int, int)}.
     */
    public void setSelection(int start, int stop) {
        Selection.setSelection(getText(), start, stop);
    }

    /**
     * Convenience for {@link Selection#setSelection(Spannable, int)}.
     */
    public void setSelection(int index) {
        Selection.setSelection(getText(), index);
    }

    /**
     * Convenience for {@link Selection#selectAll}.
     */
    public void selectAll() {
        Selection.selectAll(getText());
    }

    /**
     * Convenience for {@link Selection#extendSelection}.
     */
    public void extendSelection(int index) {
        Selection.extendSelection(getText(), index);
    }

    @Override
    public void setEllipsize(TextUtils.TruncateAt ellipsis) {
        if (ellipsis == TextUtils.TruncateAt.MARQUEE) {
            throw new IllegalArgumentException("EditText cannot use the ellipsize mode "
                    + "TextUtils.TruncateAt.MARQUEE");
        }
        super.setEllipsize(ellipsis);
    }
}

Where the trick is to refuse the InputConnection. This removes the suggestions and removes the memory leak.

Hope this helps you to..

Agaric answered 9/9, 2013 at 11:26 Comment(4)
Magic! What versions of Android have you tested this with, please?Malaria
I haven't been able to get this to work on anything I've tested on, emulators 17,18,19 and an N4.Beaux
This is the best solution for EditText Out Of Memory (Memory leaks) with Android Lollipop and below. There are plenty of discussions on this issue, but this is the only viable fix. People have even decided to give up on lollipop altogether because of this issue. Buy @Agaric a beer ! OP If you had tried this, then accept the answer.Canticle
Android 6 app with memory leaks, found by LeakCanary link in instances of android.support.v7.widget.AppCompatEditText, due to reference to destroyed Activity in View.mContext. It seems this solution works, no more leaks.Kelt
D
0

I was facing the exact same issue with a Samsung Galaxy S3.

The solution from @aslakjo didn't worked for me. I had suggestions disabled already

I ended by replacing the android:id by android:tag for the EditText in the XML layout. Now it's working fine, my fragments that were contained in a viewpager are correctly garbage collected when no longer visible, don't ask me why.

This device might register something based on the presence of an id.

Decompose answered 1/12, 2014 at 15:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.