由于AudioManager,Android Context Memory Leak ListView

我有一个ListView ,我希望在活动结束时从内存中清除它。 但是,它似乎正在泄漏。 当我检查内存转储,并获取ListViewpathToGC ,我得到以下内容,

 Class Name | Shallow Heap | Retained Heap android.widget.ExpandableListView @ 0x4063e560 | 768 | 39,904 |- list, mList com.hitpost.TeamChooser @ 0x405f92e8 | 176 | 1,648 | '- mOuterContext android.app.ContextImpl @ 0x40657368 | 160 | 304 | '- mContext android.media.AudioManager @ 0x40662600 | 40 | 168 | '- this$0 android.media.AudioManager$1 @ 0x406626b0 Unknown| 24 | 24 

我看到同样的上下文泄露在我的很多ListView's 。 诀窍是,我根本不在我的应用程序中的任何地方使用AudioManager ,根本没有来自应用程序的声音。 请帮忙,这让我发疯了。 显然是想弄清楚为什么会发生这种情况以及可能是根本问题?

Solutions Collecting From Web of "由于AudioManager,Android Context Memory Leak ListView"

与OP的泄漏无关,但是因为AudioManager导致泄漏而来到这里的人:

如果您因为使用VideoView而看到此泄漏,可能是因为此错误: https : //code.google.com/p/android/issues/detail? id = 152173

如果正在加载video,VideoView永远不会发布AudioManager。

如链接中所述,修复程序是使用ApplicationContext手动创建VideoView。

编辑:这项工作将有效,直到……如果video解码器说video有编码问题。 VideoView尝试使用应用程序上下文popupAlertDialog。 比发生崩溃。

我能想到的唯一工作就是继续使用活动上下文创建video视图,并在activity.onDestroy中,使用reflection将AudioManager的mContext设置为应用程序上下文。

注意:必须使用activity.getSystemService(Context.AUDIO_SERVICE)而不是activity.getApplicationContext.getSystemService(Context.AUDIO_SERVICE)来获取AudioManager,因为AudioManager是Context的成员variables(如果从中获取它,您将得到错误的AudioManager实例应用上下文)。

最后,您可能想知道为什么成员variables(AudioManager)阻止类(Activity)被垃圾回收。 从内存分析器,它显示AudioManager由本机堆栈拥有。 所以AudioManager不知何故没有正确清理自己。

您的代码中有几个对您未主动创建的AudioManager引用。 例如,每个可点击的View可能有一个播放onClick声音[ 来源 ]。 我猜这就是链接。

如果禁用“设置”中的单击声音,代码看起来不会创建对AudioManager引用。 您可以尝试并检查是否仍有泄漏。

泄漏的原因可能是您在ListView(适配器?)代码中持有一些View对象。 如果你保留它们,那么你可能有一个具有AudioManager 引用并保留Context引用的View

我有同样的问题,但在遵循以下建议后它就消失了。

Guy先生建议不要在调试器中进行堆转储,并在获得转储之前导致一些GC。 https://groups.google.com/forum/?fromgroups=#!topic/android-developers/ew6lfZUH0z8

在这种情况下,您可以使用应用程序上下文来避免泄漏。 我不知道为什么,但当我开始使用应用程序上下文时,问题就消失了。

我在应用程序中find的最常见原因是由于通过XML文件初始化了一些组件。 执行此操作时,将注入Activity Context ,但有时您只需要一个ApplicationContext 。 关于Android中的Web View,这种技术对我帮助很大。

我想分享一下我对同一个问题的经验,我默认在堆栈中保留一些Activity而不是完成它们。

对于那些活动,我在hprof报告中与上面提到的相同。

一旦我完成不再使用的活动,上面的参考文献没有来。 只需在不再需要时完成您的活动,就可以解决此问题。

这是一个非常基本的活动,可以复制问题(至少在Android 4.0.3上)

 public class MainActivity extends Activity { int image[]; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // setContentView(R.layout.activity_main); image = new int[1000 * 1500 * 4]; } } 

如您所见,没有与活动关联的视图或Layots,我也在系统声音设置中设置了“静音”配置文件,并关闭了“触摸时振动”。

现在,在少数(5-7取决于您的heapSize)重启后,此活动会在尝试创建新数组时生成java.lang.OutOfMemoryError。

 07-27 19:54:10.160 22542-22542/? D/dalvikvm﹕ GC_FOR_ALLOC freed 6K, 1% free 56040K/56391K, paused 25ms 07-27 19:54:10.190 22542-22542/? D/dalvikvm﹕ GC_BEFORE_OOM freed 23449K, 43% free 32591K/56391K, paused 30ms 07-27 19:54:10.260 22542-22543/? D/dalvikvm﹕ GC_CONCURRENT freed 0K, 1% free 56029K/56391K, paused 3ms+3ms 07-27 19:54:11.850 22542-22542/? D/dalvikvm﹕ GC_FOR_ALLOC freed 6K, 1% free 56040K/56391K, paused 20ms 07-27 19:54:11.880 22542-22542/? D/dalvikvm﹕ GC_BEFORE_OOM freed <1K, 1% free 56040K/56391K, paused 29ms ... Out of memory on a 24000016-byte allocation. 

转储.hprof我还看到了2个活动,其中一个活动由AudioManager持有。

调用“更新堆”然后在Android设备监视器中收集垃圾确实会从内存中删除活动,这就是logcat在此过程中声明的内容

 07-27 19:44:23.150 85-85/? I/DEBUG﹕ #06 pc 000382cc /system/lib/libdvm.so (dvmCollectGarbageInternal(GcSpec const*)+1204) 

我也尝试构建apk的发布版本,它的行为相同。 所以它不是持有引用的调试器。

这在我看来是Android中的一个错误。 解决方法是在活动的OnStop()或onFinish()中显式调用image = null。 这当然不方便。

如果您的应用程序因内存泄漏而崩溃,那么您可以使用try-catch(java.lang.outofmemory)来避免此崩溃。 事实是GC由JVM本身调用,所以程序员无法控制它。 您可以在SD卡中安装应用程序,在这种情况下将使用SD卡存储器。 不会发生内存泄漏。

只需转到您的清单文件,必须有版本号。 版本名称,还必须有“安装位置”,使其成为“preferExternal”。