【问题标题】:Memory leaking thread内存泄漏线程
【发布时间】:2013-12-18 14:41:37
【问题描述】:

在 Activity 上下文中,我有一个带有与每个选项卡关联的 TextViews 的 TabHost。目前还有一个 AsyncTask 管理 TCP 套接字,当它接收到某种信息时,它被发送到主 Activity 处理程序,后者调用一个方法将文本附加到当前 TextView。

好吧,经过一段时间(大约 5 分钟)的运行,我注意到它是如何开始挂起的,最后我得到了 ANR。因此,我安装了 Memory Analyzer for Eclipse 并与 DDMS 结合使用,我能够找出似乎是瓶颈的原因,但不知道如何处理它。

使用前面提到的工具,我可以看到数百行,就像这张照片上的那样:

顺便说一句:那张照片中有一个奇怪的细节,Thread Id 总是 1;由于在不同的线程上调用附加,每个线程不应该有所不同吗?

这数百行引用了您可能在上面的代码中看到的两个“附加”。我是线程世界的新手,所以如果你看到一些奇怪的东西,我会很感激任何建议。这是瓶颈所在的代码:

// tab = is the name of the tab where to append the new text
// line = the line to append; it may contain spans, colors, bold text, etc... that's why it's a SpannableStringBuilder
// ColorLine is a method that just returns a SpannableStringBuilder-formatted string

synchronized private static void Write2Tab(final String tab, final SpannableStringBuilder line) {
  final TabHost lth = (TabHost) activity.findViewById(android.R.id.tabhost);
  final TextView tabContent = (TextView) lth.getCurrentView();

  new Thread(new Runnable() {
    public void run() {
      String curtab = getCurrentTabName();

      // If the current tab is the one where we need to write, we do
      if (tab.equalsIgnoreCase(curtab)) {
        activity.runOnUiThread(new Runnable() {
          public void run() {
            tabContent.append(linea);
            tabContent.append((ColorLine("\n", Color.WHITE, false, 0, 1)));
          }
        });
      }
    }
  }).start();

  [...]
}

我的代码中还有 2 个内存泄漏,我能够修复,但这一次开始有点困难......关于为什么会发生这种情况以及如何修复它的任何想法?

--------------- 编辑 ---------------

在对我的应用程序泄漏进行了几天令人沮丧的研究后,我发现不止一个。我设法解决了这些问题,我最初发布的那个与 John Vint 的帖子有关,缓冲控件存在问题,导致 TextView 中的 SpannableStringBuilder 对象大量积累,所以我接受了他的帖子。现在我对另一个奇怪的泄漏有不同的问题,但它与原始帖子无关,所以我要提出一个新问题。

【问题讨论】:

  • 你在哪里调用 Write2Tab?
  • 据我所知,Java 中的内存泄漏是不可能的。您占用的所有内存都在您的控制之下,否则垃圾收集器会释放它。
  • @HAL9000 如果你一直分配内存,你的应用会因为垃圾收集器的工作而变慢。
  • 我建议您阅读维基百科上的垃圾收集和弱引用 - en.wikipedia.org/wiki/Weak_reference
  • @RobinDijkhof 这个方法是从调用 Write2Tab 的同一个 Activity 中调用的。 AsyncTask 从套接字获取线路,通过 Handler 将其发送到 MainActivity,然后调用 Write2Tab。

标签: java android multithreading memory-leaks


【解决方案1】:

StringBuilder 有多大?

如果线程卡在 253,就像它在你的堆中显示的那样愚蠢,我能想到的就是你的堆空间不足并且达到了 GC 开销限制。

如果是这种情况,您将需要缓冲 StringBuilder(即,如果长度 > N 而不是删除最旧的行,其中 N 是一个足够大的数字以具有历史记录但又足够小以防止 OOM)。

【讨论】:

  • 我实际上正在这样做,每个选项卡都有 30 行的限制。如果超过此限制,则最旧的 current_lines - 30 将被删除。这是另一个漏洞,但我能够修复它。
  • @user3001496 好的。不幸的是,没有足够的信息。看来所有东西都应该在需要的时候排队分配。
  • 注意 ThreadId: 1 可能只是表示 UI 线程。当您说runOnUiThread 时,它会将任务放在队列中,稍后再运行。
猜你喜欢
  • 2014-10-29
  • 2017-02-04
  • 2016-12-09
  • 2020-08-08
  • 2012-02-17
  • 2020-12-08
  • 2018-06-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多