由于 AudioManager 导致 Android 上下文内存泄漏 ListView

发布于 2024-11-16 20:23:21 字数 893 浏览 4 评论 0原文

我有一个 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< /代码>。诀窍在于,我根本没有在应用程序中的任何地方使用 AudioManager,应用程序根本没有声音。请帮忙,这让我发疯。显然是想弄清楚为什么会发生这种情况以及根本问题是什么?

I have a ListView and I would expect it to be cleared from memory when the activity finishes. However, it appears that it is leaking. When I check the Memory Dump, and get the pathToGC for the ListView I get the following,

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 

I see this same context leaking on a lot of of my ListView's. The trick is that, I am not using AudioManager anywhere in my app at all, no sound coming from the app at all. Please help, it's driving me crazy. Obviously trying to figure out why this is happening and what could be the root issue?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

一杯敬自由 2024-11-23 20:23:21

与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实例)应用程序上下文)。

最后,您可能想知道为什么成员变量(AudioManager)会阻止类(Activity)被垃圾收集。从内存分析器来看,AudioManager 属于本机堆栈。所以 AudioManager 不知怎的没有正确地自我清理。

Not related to OP's leak, but for people who come in here because of AudioManager causing leak:

If you see this leak because you are using VideoView, probably is because of this bug: https://code.google.com/p/android/issues/detail?id=152173

VideoView never release AudioManager if video being loaded.

the fix is, as mentioned in the link, create VideoView manually using ApplicationContext.

Edit: this work around will work, until... if the video decoder says the video has an encoding problem. VideoView tries to pop up a AlertDialog using application context. Than a crash happens.

The only work around I can think is to keep creating video view using activity context, and in activity.onDestroy, set AudioManager's mContext to application context using reflection.

Note: have to get the AudioManager using activity.getSystemService(Context.AUDIO_SERVICE) rather than activity.getApplicationContext.getSystemService(Context.AUDIO_SERVICE), since AudioManager is an member variable of Context (you will get wrong instance of AudioManager if you get it from application context).

At last, you may wonder why a member variable (AudioManager) is preventing the class (Activity) to being garbage collected. From the memory analyzer, it shows AudioManager is owned by native stack. So AudioManager somehow did not clean itself properly.

司马昭之心 2024-11-23 20:23:21

您的代码中有多个对 AudioManager 的引用,但您并非主动创建。例如,每个可点击的 View 可能都有一个播放 onClick 声音 []。我想这就是链接。

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

泄漏的原因可能是您在 ListView (适配器?)代码中保留了某些 View 对象。如果您保留它们,那么您可能会拥有一个带有 AudioManager 引用 并保留上下文参考)

There are several references to AudioManager in your code that you don't create actively. E.g. each clickable View might have one to play onClick sounds [source]. I guess that is the link.

The code looks like it would not create references to AudioManager if you disable the click sounds in your Settings. You could try that and check if there is still a leak.

The reason for your leak might be that you are holding onto some View object in your ListView (Adapter?) code. If you keep them around then you might have a View that has an AudioManager reference and that keeps a Context reference)

葮薆情 2024-11-23 20:23:21

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

Guy 先生建议不要在调试器中进行堆转储,以免在获取转储之前引发几次 GC。
https://groups.google.com/forum/?fromgroups =#!topic/android-developers/ew6lfZUH0z8

I had this same issue but it went away after following the below advice.

Mr Guy recommends not doing heap dumps in the debugger and causing a few GCs before getting the dump.
https://groups.google.com/forum/?fromgroups=#!topic/android-developers/ew6lfZUH0z8

鹤仙姿 2024-11-23 20:23:21

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

You can use application context to avoid leaks in this case. I don't know why but when I started to use application context the problem was gone.

寒冷纷飞旳雪 2024-11-23 20:23:21

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

The most common reason that I found in my application was due to initializing some components via the XML file. When you do that, the Activity Context gets injected but sometimes all you need is an ApplicationContext. With respect to the Web View in Android, this technique greatly helped me a lot.

铁憨憨 2024-11-23 20:23:21

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

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

一旦我完成不再使用的活动,上面的参考资料就不会出现。只要在不再需要时完成您的活动,这个问题就会得到解决。

I would like to share my experience regarding the same issue, I was keeping some Activity in stack by default and not finishing them.

For those activity, I was getting same as mentioned above in hprof report.

Once I finished no longer used Activities, above references did not come. Just finish your activity when it is no longer required, then this issue will be resolved.

溺深海 2024-11-23 20:23:21

这是一个非常基本的活动,可以复制该问题(至少在 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,具体取决于您的堆大小)重新启动后,此活动会在尝试创建新数组时生成 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。这当然不方便。

This is a very basic activity that replicates the issue (on Android 4.0.3 at least)

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];
    }
}

As you can see there are no Views or Layots associated with activity, also I set "Silent" profile in system Sound Settings and turned off "Vibrate on touch".

Now, after few (5-7 depending on your heapSize) restarts this activity generates the java.lang.OutOfMemoryError on trying to create new array.

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.

Dumping .hprof I also saw 2 activities, one of them is being held by AudioManager.

Calling the "Update Heap" and then Collect Garbage in Android Device Monitor really does remove the activity from memory, that is what the logcat states on this procedure

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

I have also tried to build the release version of the apk and it behaves the same. So it is not the debugger holding the reference.

This seems to me as a bug in Android. The workaround would be to explicitly call the image = null in OnStop() or onFinish() of the activity. This of course is not convenient.

甜味超标? 2024-11-23 20:23:21

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

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

If your application crashes for memory leak, then you can avoid this crash using try - catch(java.lang.outofmemory). The fact is that GC is called by JVM itself, so programer has no control on this. You can install your application in SD card, in this case SD card memory will be used. Memory leak will not occur.

Just go to your manifest file, there must be version no. version name, there also must be " Install Location" , make it "preferExternal".

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文