Android Context Memory Leak ListView 由于 AudioManager

Posted

技术标签:

【中文标题】Android Context Memory Leak ListView 由于 AudioManager【英文标题】:Android Context Memory Leak ListView due to AudioManager 【发布时间】:2011-09-20 15:56:13 【问题描述】:

我有一个ListView,我希望它会在活动完成后从内存中清除。但是,它似乎正在泄漏。当我检查内存转储并获取pathToGCListView 时,我得到以下信息,

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,应用程序根本没有声音。请帮忙,这让我发疯了。显然是想弄清楚为什么会发生这种情况以及根本问题是什么?

【问题讨论】:

是的,有静态变量,只是从具有 ListView 的活动之一中删除了所有这些变量。但同样的上下文仍在泄漏。 正如我所说,AudioManager 从字面上看绝对没有出现在我的代码中,甚至出现在我正在使用的任何库中。因此我继续困惑 你有没有想过是什么原因造成的? 我面临同样的问题。我的一项活动即使在被销毁后仍留在记忆中。 MAT 显示 AudioManager 正在持有它,我没有在任何地方使用 AudioManager。对此有何想法? 我也有这个问题...有什么解决办法吗?真的很烦人......我的很多活动无缘无故地跟不上这个问题 【参考方案1】:

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

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

如果视频正在加载,VideoView 永远不会释放 AudioManager。

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

编辑:此解决方法将起作用,直到...如果视频解码器说视频存在编码问题。 VideoView 尝试使用应用程序上下文弹出一个 AlertDialog。然后发生崩溃。

我能想到的唯一解决方法是继续使用活动上下文创建视频视图,并在 activity.onDestroy 中,使用反射将 AudioManager 的 mContext 设置为应用程序上下文。

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

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

【讨论】:

【参考方案2】:

您的代码中有几个对AudioManager 的引用不是您主动创建的。例如。每个可点击的View 可能都有一个可以播放 onClick 声音 [source]。我想这是链接。

如果您在“设置”中禁用点击声音,该代码似乎不会创建对AudioManager 的引用。你可以试试看是否还有泄漏。

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

【讨论】:

我认为大多数应用程序都有同样的问题。 我认为答案不应该围绕上下文展开。 AudioManager 是一个单例类和一个系统类。垃圾收集器知道这一点并相应地执行适当的收集。您需要做的就是在转储内存之前执行一次 GC 调用。【参考方案3】:

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

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

【讨论】:

【参考方案4】:

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

【讨论】:

【参考方案5】:

我在应用程序中发现的最常见原因是通过 XML 文件初始化了一些组件。当你这样做时,Activity Context 会被注入,但有时你只需要一个ApplicationContext。对于 Android 中的 Web View,这个技术对我帮助很大。

【讨论】:

【参考方案6】:

我想分享我对同一问题的经验,默认情况下我将一些 Activity 保留在堆栈中并且没有完成它们。

对于这些活动,我得到的结果与上面 hprof 报告中提到的相同。

一旦我完成不再使用的活动,上面的引用就没有了。在不再需要的时候完成你的活动,然后这个问题就会得到解决。

【讨论】:

【参考方案7】:

这是一个复制问题的非常基本的活动(至少在 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];
    

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

现在,在几次(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。这当然不方便。

【讨论】:

【参考方案8】:

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

只要去你的清单文件,必须有版本号。版本名称,还必须有“安装位置”,改成“preferExternal”。

【讨论】:

我认为这不能回答我的问题。 @santanu, 您可以在 SD 卡中安装您的应用程序,在这种情况下将使用 SD 卡内存。不会发生内存泄漏。什么鬼? @haibison 内存泄漏是different。这是关于 RAM 被不必要地使用,与 SD 卡无关。 @zapl,谢谢 :-) 我明白这一点。我只是对他的信息感到困惑。 @haibison 哎呀,这是一个报价。我已经想知道你们都对 sd 卡有什么了解

以上是关于Android Context Memory Leak ListView 由于 AudioManager的主要内容,如果未能解决你的问题,请参考以下文章

用verilog写的ROM用quartusII综合后为啥没综合到memory bit里而是综合到了LE里面要怎样才能弄到memory

[CodeForces - 712D]Memory and Scores (DP 或者 生成函数)

UnityVR一体机报错:GL_OUT_OF_MEMORY,[EGL] Unable to acquire context

Ubuntu elasticsearch max virtual memory areas vm.max_map_count [65530] is too low, increase to at le

android存储的理解

codeforces 712C C. Memory and De-Evolution(贪心)