如何判断哪些线程正在产生所有垃圾?

Posted

技术标签:

【中文标题】如何判断哪些线程正在产生所有垃圾?【英文标题】:How to tell which thread(s) are producing all the garbage? 【发布时间】:2011-02-24 11:23:26 【问题描述】:

我有一个大约有 15 个线程的应用程序。大多数人做着平凡的工作,大部分时间都在睡觉。其他人收集信息并将其缓存在哈希图中。哈希图增长到中等大小并趋于平稳。键的数量和值的大小保持不变,但值的内容会发生变化(平均每秒 33 个键)。

当我启动我的应用程序时,我注意到垃圾收集间隔从几分钟变为每秒一次,每次垃圾量为 700k+。

事实上,当我写这篇文章时,它导致我的手机重新启动并出现错误“Referencetable Overflow”。

这是我的问题:是否有任何技巧可以识别哪些线程正在产生垃圾,甚至更多地了解它们正在产生什么垃圾?

05-26 22:08:57.052 W/dalvikvm( 1031): ReferenceTable overflow (max=512)
05-26 22:08:57.052 W/dalvikvm( 1031): Last 10 entries in JNI local reference table:
05-26 22:08:57.052 W/dalvikvm( 1031):   502: 0x449904a8 cls=Ljava/lang/String; (28 bytes)
05-26 22:08:57.052 W/dalvikvm( 1031):   503: 0x4494fda8 cls=Ljava/lang/String; (28 bytes)
05-26 22:08:57.052 W/dalvikvm( 1031):   504: 0x44a172c8 cls=Ljava/lang/String; (28 bytes)
05-26 22:08:57.052 W/dalvikvm( 1031):   505: 0x448c7900 cls=Ljava/lang/String; (28 bytes)
05-26 22:08:57.052 W/dalvikvm( 1031):   506: 0x44842b18 cls=Ljava/lang/String; (28 bytes)
05-26 22:08:57.052 W/dalvikvm( 1031):   507: 0x448e9eb8 cls=Ljava/lang/String; (28 bytes)
05-26 22:08:57.052 W/dalvikvm( 1031):   508: 0x449c6ae0 cls=Ljava/lang/String; (28 bytes)
05-26 22:08:57.052 W/dalvikvm( 1031):   509: 0x44998138 cls=Ljava/lang/String; (28 bytes)
05-26 22:08:57.052 W/dalvikvm( 1031):   510: 0x44961ae0 cls=Ljava/lang/String; (28 bytes)
05-26 22:08:57.052 W/dalvikvm( 1031):   511: 0x448ee470 cls=Ljava/lang/String; (28 bytes)
05-26 22:08:57.060 W/dalvikvm( 1031): JNI local reference table summary (512 entries):
05-26 22:08:57.060 W/dalvikvm( 1031):   487 of Ljava/lang/String; 28B (487 unique)
05-26 22:08:57.060 W/dalvikvm( 1031):    25 of Ljava/lang/String; 36B (25 unique)
05-26 22:08:57.060 W/dalvikvm( 1031): Memory held directly by native code is 14536 bytes
05-26 22:08:57.068 E/dalvikvm( 1031): Failed adding to JNI local ref table (has 512 entries)
05-26 22:08:57.068 I/dalvikvm( 1031): "BT EventLoop" prio=5 tid=81 RUNNABLE
05-26 22:08:57.068 I/dalvikvm( 1031):   | group="main" sCount=0 dsCount=0 s=N obj=0x447cd620 self=0x4d7b38
05-26 22:08:57.068 I/dalvikvm( 1031):   | sysTid=1138 nice=0 sched=0/0 cgrp=default handle=4210840
05-26 22:08:57.068 I/dalvikvm( 1031):   at dalvik.system.NativeStart.run(Native Method)
05-26 22:08:57.068 I/dalvikvm( 1031): 
05-26 22:08:57.068 E/dalvikvm( 1031): VM aborting
05-26 22:08:57.185 I/DEBUG   (  990): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***

【问题讨论】:

应该有参考表摘要打印到logcat日志中。里面有什么? 添加了参考表的详细信息。 将引用表溢出隔离为蓝牙相关。提交的 android 错误报告:code.google.com/p/android/issues/detail?id=8676 是的,我猜这是蓝牙实现中的错误 JNI 代码。它溢出了 JNI 本地引用表,当您有一个循环且永不返回的本机方法时,这很容易做到。 【参考方案1】:

有Allocation Tracker。

另一件需要考虑的事情,您是否尝试过在哈希图中使用WeakReferences

【讨论】:

分配跟踪器+1。我仍然试图围绕weakReferences,但我失败了。我将尝试使用 Allocation Tracker 并让这个问题不再回答一段时间,以了解其他观点。 分配跟踪器文章很棒。这就是我需要阐明这个问题的原因。谢谢。

以上是关于如何判断哪些线程正在产生所有垃圾?的主要内容,如果未能解决你的问题,请参考以下文章

深入理解java虚拟机 - 垃圾回收机制(GC)

垃圾收集器和内存分配

GC是如何判断一个对象为"垃圾"的?被GC判断为"垃圾"的对象一定会被回收吗?

JVM如何判断哪些对象可以被回收

2垃圾回收与算法

JVM内存回收区域+对象存活的判断+引用类型+垃圾回收线程