【问题标题】:Memory Leaks & OutOfMemoryError内存泄漏和 OutOfMemoryError
【发布时间】:2018-02-13 14:59:15
【问题描述】:

所以我试图找出为什么我的应用程序崩溃了

Fatal Exception: java.lang.OutOfMemoryError: Failed to allocate a 128887990 byte allocation with 16777216 free bytes and 76MB until OOM
   at java.lang.AbstractStringBuilder.enlargeBuffer(AbstractStringBuilder.java:95)
   at java.lang.AbstractStringBuilder.append0(AbstractStringBuilder.java:146)
   at java.lang.StringBuilder.append(StringBuilder.java:216)    

我已经阅读了几篇文章,但它们都指向位图图像,我没有使用任何位图,所以我想也许我有可能导致这种情况的内存泄漏,所以我安装了泄漏 Canary,它只显示以下泄漏:

com.google.android.gms.internal.zzcfi.zzfus
references com.google.android.gms.common.api.internal.zzci.zzful
references com.google.android.gms.common.api.internal.zzck.zzfuk
com.tech.activity.dashboard instance

我在 Google、Stackoverflow、Github 和泄漏金丝雀上进行了搜索,但我找不到关于这究竟是什么泄漏或如何修复它的参考。我相信这是来自我的google play services location,但这会导致我看到的 OOM 错误吗?有人能指出我正确的方向吗?

** 编辑 ** 正如评论指出这应该是一个字符串生成器问题,自从我第一次发布应用程序以来,我从未改变我的字符串生成器的工作方式,这是我的Stringbuilder,其来源来自AccessibilityNodeInfo,我在做什么错了吗?

public void processEvent(final AccessibilityNodeInfo source)
{
    final StringBuilder sb = new StringBuilder();
    processSubEvent(source, 0, sb);

    processUIText(source, sb.toString().toLowerCase());
}

private void processSubEvent(final AccessibilityNodeInfo source, final int n, final StringBuilder sb) {
    for (int i = 0; i < n; ++i){
        sb.append("\t");
    }

    if (source != null){
        sb.append(tools.getText(source));
        sb.append("\n");
        final int childCount = source.getChildCount();

        for (int i = 0; i < childCount; i++)
        {
            //Log.e(TAG, "Last UI: " + lastUIText);
            AccessibilityNodeInfo child = source.getChild(i);
            processSubEvent(child, n + 1, sb);

            child.recycle();
            }
        }
}

这是如何使用信息的示例:

private void processUIText(AccessibilityNodeInfo source, final String text)
{
   if (text.contains("hello") && !text.contains("hello again"){
        tools.showToast("Hello Reached");
   }
}

【问题讨论】:

  • 这不是内存泄漏的问题。这是试图分配过多内存的问题。单个分配中的 128,887,990 字节太大。您需要修复您对 StringBuilder 所做的任何事情,以免尝试构建如此大的内存字符串。
  • 我已经更新了我的代码,请看更新,我在那里做错了吗?
  • 这种深度优先递归树算法的结果是你试图生成一些大字符串。那是行不通的。您可能需要切换到广度优先方法,因此一旦字符串达到某个特定大小,您就可以停止深入树中。或者,也许您一开始就不应该生成一个大字符串(例如,将其写入文件,生成一些其他数据结构)。
  • 关于如何解决这个问题的任何建议?我的sb.length() 只显示 799,而我的childcount 只显示 17。这似乎不会有那么多内存。我看到其他人发帖说他们有超过 10000 个。
  • “关于如何解决这个问题的任何建议?” ——我已经提供了一些。 “我的 childcount 只显示 17”——树中的每个节点都有一个 childcount 值,而不仅仅是一个。

标签: android memory-leaks out-of-memory


【解决方案1】:

这是如何使用信息的示例:

然后不要构建字符串。建立一个boolean。类似的东西应该可以工作:

class Whatever {
    private boolean helloSeen=false;
    private boolean helloAgainSeen=false;

    public void processEvent(final AccessibilityNodeInfo source)
    {
        processSubEvent(source);
    }

    private void processSubEvent(final AccessibilityNodeInfo source) {
        if (source != null){
            String text=tools.getText(source);

            if (text.contains("hello")) {
                helloSeen=true;
            }

            if (text.contains("hello again")) {
                helloAgainSeen=true;

            }

            if (!helloSeen || !helloAgainSeen) {
                final int childCount = source.getChildCount();

                for (int i = 0; i < childCount; i++)
                {
                    //Log.e(TAG, "Last UI: " + lastUIText);
                    AccessibilityNodeInfo child = source.getChild(i);
                    processSubEvent(child);

                    child.recycle();
                }
            }
        }
    }
}

processEvent() 返回后,helloSeenhelloAgainSeen 将反映您的消息是否在任何地方遇到过。

【讨论】:

    猜你喜欢
    • 2014-05-18
    • 2012-08-07
    • 1970-01-01
    • 2010-12-02
    • 2013-11-08
    • 2016-05-03
    • 2011-11-25
    • 2010-11-19
    • 2014-09-27
    相关资源
    最近更新 更多