在这个问题上花了3天时间,我很难过,可以继续使用你的帮助。
我的应用使用包含片段管理器的单个活动。在目前的状态下,我设计它只能在任何时候连接一个片段。我打电话给:
getSupportFragmentManager().beginTransaction().replace(R.id.main_fragment, mCurrent).commit();
删除现有片段并将其替换为新片段。片段不会存储在其他任何地方。 (只有mCurrent和在下一个片段打开时被替换的事务管理器)
发生的问题不是OutOfMemory异常,而是整个应用程序重新启动,因为设备本身内存不足。除了像DeadObjectException和
这样的东西之外,日志什么也没说9-17 11:34:14.742: W/InputDispatcher(341): channel ~ Consumer closed input channel or an error occurred. events=0x9
09-17 11:34:14.742: E/InputDispatcher(341): channel ~ Channel is unrecoverably broken and will be disposed!
这些来自设备日志,而不是我的应用日志。而且他们没有为我提供足够的信息来追踪导致他们的原因。应用程序的内存永远不会被释放,平板电脑从那时起就无法使用。
我已经使用了我所知道的所有工具来分析内存泄漏会是什么,但没有什么突出的。我使用MAT(MemoryAnalyzerTool)和Eclipse DDMS工具来找出可能出错的地方。在我访问许多不同的片段后,MAT报告使用的总内存为8MB-16MB。我看一下泄漏报告,看起来没什么特别的。图像视图大约3MB,位图大约3MB,其他大小为8MB。在DDMS中,堆表示我使用了应用程序分配大小的约50%。当我在运行进程中查看“设置”时,我访问的每个片段都会使我的应用程序的内存量在30-140MB之间波动,但设备本身的内存不会减少,因此设备内存耗尽的原因。即使应用程序完全关闭,退出,销毁,内存也永远不会被释放。即使所有当前运行的应用程序的总和大约为200-300MB,也会使用所有759MB。
我的假设是它要么在内存中保留片段本身,要么在这些片段中包含某些内容,即使我的应用不是。我在每个片段交换后调用GC。
我正在使用三星Galaxy Tab 2 10.1“,但摩托罗拉Xoom也出现同样的问题。
问题:
感谢您的时间。
答案 0 :(得分:0)
本机代码中的内存泄漏可能会产生您所描述的症状:系统内存慢慢消失,而应用程序的内存占用(如JVM所示)或多或少保持不变。
我建议仔细查看本机代码中的内存分配,并验证每个代码是否正在清理。这包括对malloc
的调用,在堆上创建的任何对象(即,使用“new”),等等。有一些工具支持使用DDMS分析本机分配 - 请参阅this answer。
答案 1 :(得分:0)
经过进一步分析,我可以推断出我的内存泄漏存在三个主要问题:
我最初将所有UI创建代码放在Overridden onStart方法中,因为我不清楚它的适当位置(onStart vs onCreateView)。我将所有UI代码移动到onCreateView(与this.getView()相关的任何内容 - >在onCreateView中使用你的inflater)。这似乎消除了每次我打开并持续关闭应用程序时发生的内存泄漏。这是一个建议:
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View v = inflater.inflate(R.layout.fragment_one, container, false);
//ALL UI code here using "v"
return v;
}
我使用ViewPager来容纳我的所有片段(这是因为我需要的特定导航类型)。我将其切换为使用自定义片段管理解决方案。我建议使用片段事务管理器(我最初认为片段管理器导致泄漏,但它似乎不是)。这并没有导致泄漏,但却占用了大量的记忆。
WebViews也是内存泄漏的重要原因(因为它已在整个互联网上得到充分记录)。我尝试使用一个解决方案,将webview包装在容器中并销毁webview及其容器(这是代码)
@Override
public void onDestroy()
{
super.onDestroy();
if (mWebContainer != null)
mWebContainer.removeAllViews();
if (mWebView != null)
{
mWebView.loadUrl("about:blank");
mWebView.destroy();
mWebView = null;
}
}
这并没有解决我的webview问题,但也许它会修复别人的问题。我正在继续寻找这个问题。我的场景包括多个片段,每个片段都有一个webview,可以使用webview打开其他片段。
我希望这有助于其他人,我被困了一个多月调试所有不同的情况导致泄漏,因为我最初没有考虑到有很多原因。祝好运。一如既往地感谢SO社区。 p>
答案 2 :(得分:0)
我发现了内存泄漏的主要原因。它是通过创建Process对象并打开输入和输出流来执行shell命令。我用它来检测有根设备。我不足以成为Process类的专家来解释为什么会导致泄漏(我现在要读它),但是如果你使用的代码与此类似,我会对这个问题保持警惕。
public static enum SHELL_COMMAND
{
check_su_binary(new String[] { "/system/xbin/which", "su" }), ;
String[] command;
SHELL_COMMAND(String[] command)
{
this.command = command;
}
}
/**
* @param shellCommand
* @return
*/
public List<String> executeCommand(SHELL_COMMAND shellCommand)
{
//this code was causing my memory leak
try
{
String line = null;
List<String> fullResponse = new ArrayList<String>();
Process localProcess = Runtime.getRuntime().exec(shellCommand.command);
OutputStreamWriter writer = new OutputStreamWriter(localProcess.getOutputStream());
BufferedWriter bufferedWriter = new BufferedWriter(writer);
InputStreamReader reader = new InputStreamReader(localProcess.getInputStream());
BufferedReader in = new BufferedReader(reader);
while ((line = in.readLine()) != null)
{
fullResponse.add(line);
}
}
catch (Exception e)
{
e.printStackTrace();
}
try
{
bufferedWriter.close();
bufferedWriter = null;
writer.close();
writer = null;
in.close();
in = null;
reader.close();
reader = null;
}
catch (IOException e)
{
e.printStackTrace();
}
return fullResponse;
}