2

在这个问题上花了 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 之间。我查看了泄漏报告,似乎没有什么异常。Imageviews 大约 3MB,Bitmaps 大约 3MB,其他大约 8MB。在 DDMS 中,堆说我正在使用应用程序分配大小的约 50%。当我查看正在运行的进程的设置时,我访问的每个 Fragment 都会使我的应用程序的内存量在 30-140MB 之间波动,但是设备本身的内存永远不会减少,这就是设备内存不足的原因。即使应用程序完全关闭、退出、销毁,内存也永远不会释放。

我的假设是它要么在内存中保留片段本身,要么在这些片段中包含某些内容,即使我的应用程序不是。我在每次片段交换后调用 GC。

我使用的是三星 Galaxy Tab 2 10.1",但同样的问题出现在摩托罗拉 Xoom 上。

问题:

  1. 有没有人经历过这种行为?
  2. 任何人都可以向我提供有关其他工具的任何指导,以帮助我研究可能的内存泄漏吗?
  3. 是否有可以查看的系统进程详细显示设备内存是如何分配的?

谢谢你的时间。

4

3 回答 3

0

本机代码中的内存泄漏可能会产生您所描述的症状:系统内存慢慢流失,而应用程序的内存占用(如 JVM 所见)或多或少保持不变。

我建议仔细查看本机代码中的内存分配,并验证每个内存分配是否都已被清理。这包括对 的调用malloc、在堆上创建的任何对象(即,使用“new”)等等。有一些工具支持使用 DDMS 分析本机分配 - 请参阅此答案

于 2013-09-19T14:19:09.190 回答
0

经过进一步分析,我可以推断出我的内存泄漏存在三个主要问题:

  1. 我最初将所有 UI 创建代码放在 Overridden onStart 方法中,因为我不清楚它的适当位置(onStart 与 onCreateView)。我将所有 UI 代码移到 onCreateView 中(与 this.getView() 相关的任何内容 -> 在 onCreateView 中使用您的充气机)。这似乎消除了每次我连续打开和关闭应用程序时发生的内存泄漏。这里有一个建议:

    @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;
    }
    
  2. 我使用 ViewPager 来容纳我的所有片段(这是因为我需要特定类型的导航)。我将其切换为使用自定义片段管理解决方案。我会推荐使用片段事务管理器(我最初认为片段管理器导致了泄漏,但似乎并非如此)。这不会导致泄漏,但会占用大量内存。

  3. 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,可以打开带有 webviews 的其他片段。

我希望这对其他人有所帮助,我被困了一个多月,调试所有导致泄漏的不同场景,因为我最初并没有考虑到有很多原因。祝你好运。一如既往地感谢 SO 社区。

于 2013-10-07T21:23:48.003 回答
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;
}
于 2013-12-12T16:36:55.290 回答