【问题标题】:Android Context Memory Leak ListView due to AudioManagerAndroid Context Memory Leak ListView 由于 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。对此有何想法?
  • 我也有这个问题...有什么解决办法吗?真的很烦人......我的很多活动无缘无故地跟不上这个问题

标签: android listview memory-leaks android-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 卡有什么了解
              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2020-06-30
              • 2022-12-19
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2018-10-04
              相关资源
              最近更新 更多