由于AudioManager,Android Context Memory Leak ListView

时间:2011-06-22 18:56:23

标签: android listview memory-leaks android-audiomanager

我有ListView,我希望在活动结束时从内存中清除它。但是,它似乎正在泄漏。当我检查内存转储,并获得pathToGC的{​​{1}}时,我得到以下内容,

ListView

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

8 个答案:

答案 0 :(得分:8)

与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不知何故没能正常清理。

答案 1 :(得分:5)

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

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

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

答案 2 :(得分:4)

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

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

答案 3 :(得分:1)

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

答案 4 :(得分:0)

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

答案 5 :(得分:0)

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

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

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

答案 6 :(得分:0)

这是一个非常基本的活动,可以复制问题(至少在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。这当然不方便。

答案 7 :(得分:-4)

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

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