我遇到了恼人的内存泄漏和崩溃,这似乎是一个平台错误。我正在尝试调试/另一个/内存问题,但我不断发现与 EditText 相关的错误,从而保留了我的 View 以及其中的 View 。
给定一个 DialogFragment、一个带有 EditText 和 UI Monkey 的布局,我可以使以下简单的应用程序因内存不足异常而崩溃。
我已经在 x86 模拟器 17 - 19 上进行了测试,最新更新截至 2014 年 3 月 21 日,堆大小为 16MB。在 4.4.2 的 Nexus 4 上,我看到内存泄漏在五分钟内不断增加,但从未停留足够长的时间以使其崩溃,但在查看 N4 的内存转储时,显示了相同的泄漏。/p>
当按下选项菜单时,Activity 将打开一个 DialogFragment:
package org.example.edittextoom;
import android.app.Dialog;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentActivity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
public class MainActivity extends FragmentActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
DialogFragment df = new Df();
df.show(getSupportFragmentManager(), "dialogtag");
return true;
}
public static class Df extends DialogFragment {
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
Dialog onCreateDialog = super.onCreateDialog(savedInstanceState);
return onCreateDialog;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Using inflator from app context instead to attempt to avoid the issue with EditTexts holding onto Activity's
View view = LayoutInflater.from(
getActivity().getApplicationContext()).inflate(
R.layout.dialog, container, false);
// Since disabling no suggestions is suppose to prevent the edit text leak
EditText et = (EditText) view.findViewById(R.id.editText1);
int it = et.getInputType();
et.setInputType(it | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
it = et.getInputType();
return view;
}
}
}
这两种布局都很简单。该对话有一个 EditText。
activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
</RelativeLayout>
dialog.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<EditText
android:id="@+id/editText1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:inputType="text|textNoSuggestions"
/>
</RelativeLayout>
让我们通过运行 UI Monkey 来查看内存泄漏情况。
adb shell monkey -p org.example.edittextoom --pct-nav 0 --pct-majornav 0 --pct-appswitch 0 800000
(如果您要运行此程序,请在屏幕尺寸最小的 x86 模拟器上运行,以提高速度。)
当它运行时,您还可以通过查看此处的第五列来确认它占用的内存量正在增加,大约需要一分钟左右(顺便说一句,它通常会在大约 56000 时崩溃):
$ adb shell ps | grep edittext
u0_a46 2727 794 177888 31596 ffffffff b7f34997 S com.example.edittextoom
$ adb shell ps | grep edittext
u0_a46 2727 794 177888 31784 ffffffff b7f3322a S com.example.edittextoom
$ adb shell ps | grep edittext
u0_a46 2727 794 177956 31852 ffffffff b7f34997 S com.example.edittextoom
$ adb shell ps | grep edittext
u0_a46 2727 794 178124 32064 ffffffff b7f3322a S com.example.edittextoom
然后它最终会崩溃(我发现大约事件 150,000 到 500,000)输出:
// CRASH: com.example.edittextoom (pid 13620)
// Short Msg: java.lang.OutOfMemoryError
// Long Msg: java.lang.OutOfMemoryError
// Build Label: generic_x86/sdk_x86/generic_x86:4.2/JOP40C/eng.android-build.20121231.103448:eng/test-keys
// Build Changelist: eng.android-build.20121231.103448
// Build Time: 1356921334000
// java.lang.OutOfMemoryError
// at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
// at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:502)
// at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:355)
// at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:785)
// at android.content.res.Resources.loadDrawable(Resources.java:1965)
// at android.content.res.Resources.getDrawable(Resources.java:660)
// at com.android.internal.policy.impl.PhoneWindow.generateLayout(PhoneWindow.java:2832)
// at com.android.internal.policy.impl.PhoneWindow.installDecor(PhoneWindow.java:2875)
// at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:285)
// at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:279)
// at android.app.Dialog.setContentView(Dialog.java:482)
// at android.support.v4.app.DialogFragment.onActivityCreated(DialogFragment.java:366)
// at android.support.v4.app.Fragment.performActivityCreated(Fragment.java:1508)
// at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:947)
// at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1104)
// at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:682)
// at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1467)
// at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:440)
// at android.os.Handler.handleCallback(Handler.java:725)
// at android.os.Handler.dispatchMessage(Handler.java:92)
// at android.os.Looper.loop(Looper.java:137)
// at android.app.ActivityThread.main(ActivityThread.java:5039)
// at java.lang.reflect.Method.invokeNative(Native Method)
// at java.lang.reflect.Method.invoke(Method.java:511)
// at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
// at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
// at dalvik.system.NativeStart.main(Native Method)
//
** Monkey aborted due to error.
Events injected: 131816
:Sending rotation degree=0, persist=false
:Dropped: keys=1534 pointers=13377 trackballs=0 flips=0 rotations=0
## Network stats: elapsed time=308525ms (0ms mobile, 0ms wifi, 308525ms not connected)
** System appears to have crashed at event 131816 of 800000 using seed 1393322223373
(有时模拟器会不断占用内存,并杀死应用程序,但您不会强制关闭对话,因此 UI Monkey 会进入循环,玩模拟器,直到再次启动应用程序,但不管怎样,应用程序占用这么多内存后就会被系统杀死。)
如果您停止 UI Monkey 中流,通过取消其进程,您可以检查 MAT 中的 hprof 以查看占用内存的内容(我退出应用程序并在查看 hprof 之前执行强制 gc),以查看它仅保留一个 MainPageActivity,但保留 63 个 MainPageActivity$Df 实例,而且这是在运行仅一分钟左右之后的结果。我在 Nexus 4 上查看内存转储时也得到同样的结果。
如果您列出对其中之一的传入引用,然后单击“GC 根路径”并排除弱引用和软引用,您会得到以下结果(与我所看到的所有其他 63 个引用相同):
但是,如果我将对话框中的 EditText 更改为带有 id 的 ProgressBar 或带有 id 的 TextView,则不会出现 MAT 中显示的崩溃或内存泄漏问题。所以我相信这与此有关EditText causing memory leak但是,所有解决方法都不起作用,既不使 EditText 的 InputConnection 为空,也不关闭建议(我在上面的示例中已完成)。如果我删除 EditText 的 id,我也设法摆脱泄漏,但随后我无法访问我的 EditText。
您是否见过类似的情况,是否找到了解决方法,或者您是否可以在我的代码中看到一些疏忽?
此问题目前导致我无法正确查找应用程序中的内存泄漏。
最佳答案
我也遇到了同样的问题。由于编辑器内的闪烁,对话框内的 EditText 会泄漏内存。这种情况发生在 Samsung Tab 10 4.4.2 上,但没有发生在 Nexus 7 4.4.2 上,这很奇怪。
解决这个问题的唯一方法是禁用 EditText 中的光标。使用 setCursorVisible(false)。如果您希望光标闪烁,可以在关闭对话框之前禁用光标,这样可以防止 Blinker 再次自行调度。
注意:rana 的建议显然是错误的。他根本不明白静态嵌套类和非静态内部类之间的区别。非静态内部类将保留对您的 Activity 的隐式引用,因此实际上您确实希望在此处使用静态嵌套类,这与在单独的文件中声明此类相同。
关于android - EditText 和 DialogFragment 导致 OutOfMemory 崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22339458/