说明:
我有一个具有以下结构的应用: ActionBar up(ActionBarSherlock) 下面的ViewPagerIndicator(用于标签) ViewPager(托管片段)
我有一个问题,我的一个片段导致了相当大的内存泄漏。我将问题缩小到以下情况:
导致泄漏的片段只会在其onCreateView
方法中使布局膨胀。这是通过以下方式完成的:
return inflater.inflate(R.layout.filter_auctions_fragment, container, false);
这里没什么不寻常的。
布局文件中只包含ScrollView
,LinearLayout
和两个EditText
(包含更多通常的内容,但我将问题缩小到这些视图以简化这些操作)
现在用于添加片段的代码: mTabsAdapter.addTab(tabName,ProblematicFragment.class);
mTabsAdapter
是TabsAdapter
的一个实例,这是一个扩展支持库FragmentPagerAdapter
的类。这是相当标准的,所以我不包括使这个问题尽可能短的来源。
现在有趣的部分:
当我来回旋转设备几次时,堆就会发生这种情况:
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
显然,内存泄漏。
是的,我知道它会导致Activity从头开始重新创建,这就是我想要的,因为我有不同的横向和纵向模式布局。尽管如此,它不应该导致内存泄漏。
我找到了这个问题的根源。这是我前面提到的两个EditText
。只要我从布局中删除它们并进行相同的测试(来回旋转)。这些是我得到的GC消息:
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
现在这就是我想要看到的东西!
WHY!吗
有人可以告诉我为什么会这样吗?我想补充一点,我没有在我的应用程序的任何地方保留对这些EditText
对象的引用(我通常这样做,但即使我为了测试目的而删除了所有这些,但仍然会发生泄漏)。
奖金 - MAT泄漏的屏幕截图:
正如您所看到的,片段和活动有16个实例,而应该只有一个。
修改
我注意到当我在不同的活动中手动添加片段(使用FragmentManager.beginTransaction()
)时,不会发生泄漏!我现在完全糊涂了......
EDIT2:
删除android:id
的{{1}}属性修复了它......但现在它们已经没用了......
答案 0 :(得分:8)
我找到了符合我需求的解决方案。
我将问题追溯到widget.EditableInputConnection
。我认为在建议系统中查找。它还负责保持我的Activity,从而导致内存泄漏。
我不需要这些建议,所以我想将其关闭。然而事实证明这很困难。 EditText.setInputType
在xml和代码中都不起作用。
我最终做了以下事情。神奇的事情发生在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);
}
}
诀窍是拒绝InputConnection。这将删除建议并消除内存泄漏。
希望这有助于你......
答案 1 :(得分:0)
我遇到了与三星Galaxy S3完全相同的问题。
solution from @aslakjo对我不起作用。我已经禁用了建议
我最后将android:id
替换为android:tag
,用于XML布局中的EditText
。现在它工作正常,我在查看器中包含的片段在不再可见时被正确地收集垃圾,不要问我原因。
此设备可能会根据id
的存在来注册某些内容。