由于 AudioManager 导致 Android 上下文内存泄漏 ListView
我有一个 ListView,我希望在活动完成时将其从内存中清除。然而,它似乎正在泄漏。当我检查内存转储并获取 ListView
的 pathToGC
时,我得到以下信息,
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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(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实例)应用程序上下文)。
最后,您可能想知道为什么成员变量(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.
您的代码中有多个对
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 clickableView
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 aView
that has anAudioManager
reference and that keeps aContext
reference)我也遇到了同样的问题,但在遵循以下建议后它就消失了。
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
在这种情况下,您可以使用应用程序上下文来避免泄漏。我不知道为什么,但是当我开始使用应用程序上下文时,问题就消失了。
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.
我在应用程序中发现的最常见原因是通过 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 anApplicationContext
. With respect to the Web View in Android, this technique greatly helped me a lot.我想分享我对同一问题的经验,默认情况下我在堆栈中保留一些活动而不是完成它们。
对于这些活动,我得到的结果与上面 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.
这是一个非常基本的活动,可以复制该问题(至少在 Android 4.0.3 上)
正如您所看到的,没有与活动关联的视图或布局,我还在系统声音设置中设置了“静音”配置文件并关闭了“振动”触碰”。
现在,在几次(5-7,具体取决于您的堆大小)重新启动后,此活动会在尝试创建新数组时生成 java.lang.OutOfMemoryError 。
转储.hprof 我还看到了 2 个活动,其中之一是由 AudioManager 举办的。
调用“更新堆”,然后在 Android 设备监视器中收集垃圾确实会从内存中删除活动,这就是 logcat 在此过程中的状态,
我也尝试构建 apk 的发行版本,它的行为是相同的。所以它不是调试器持有引用。
在我看来,这是 Android 中的一个错误。解决方法是在活动的 OnStop() 或 onFinish() 中显式调用 image = null。这当然不方便。
This is a very basic activity that replicates the issue (on Android 4.0.3 at least)
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.
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
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.
如果您的应用程序因内存泄漏而崩溃,那么您可以使用 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".