MediaPlayer源码存在的内存泄漏问题,释放资源的正确方式
2017-03-03 18:49
911 查看
最近完成了一个联网的视频播放器Demo,闲来无聊,尝试了一下LeakCanary,一款Android查看内存泄漏的工具。使用方式
https://www.liaohuqiu.net/cn/posts/leak-canary-read-me/
这个是LeakCanary的中文使用文档,很简单。
无意间发现应用存在内存泄漏问题。
LeakCanary提供的Log信息:
可以看到,这个工具很强大很方便,直接指出了内存泄漏的地方,上面写的很清楚,倒数第二行说明了Mediaplayer存在一个代理引用,导致了PlayActivity无法回收,造成内存泄漏。
按理说,既然工具已经这么详细的说明了内存泄漏出现问题的地方,问题应该很好解决,但是,我查看了我的代码,mediaplayer容易出现内存泄漏的地方无非就是在和Activity进行生命周期的时候,需要自己进行释放资源,不然会造成内存泄漏。
附上我的关键代码吧:
可以看到我重写了Activity的生命周期,在OnDestroy方法中释放了Mediaplayer的资源,释放Mediaplayer的资源的方法也是网络上常用的释放Meidplayer的步骤。但是问题来了,这样怎么会造成内存泄漏哪?
最后,还是老外厉害啊,在stackoverflow上找到一篇文章,问题一模一样,原文链接
![](https://oscdn.geek-share.com/Uploads/Images/Content/201703/03/fd4b602e96051430b816fe9a17dcefa4)
大概意思是,他查看了Mediaplayer的源码,发现存在一个引用,应该回收,但是在release方法中,并没有没处理,只有在reset方法中,这个引用才被消除。
所以结论来了:释放资源的正确方式:
具体到源码,是哪一个没有回收,大概看了一下
Mediaplayer的release源码:
reset的源码:
我查了reset中的对象,发现mSubtitleController 这个对象在release方法中没有被处理,只在reset方法中被reset了,并且mSubtitleController 的构造方法会存在context对象,我猜应该就是这个对象,导致内存泄漏这个问题存在吧
问题的正确与否,具体源码原理和原因待求大神解释。
https://www.liaohuqiu.net/cn/posts/leak-canary-read-me/
这个是LeakCanary的中文使用文档,很简单。
无意间发现应用存在内存泄漏问题。
LeakCanary提供的Log信息:
03-03 14:31:06.281 20734-27495/com.shuyu.video.clean.debug D/LeakCanary: In com.shuyu.video.clean.debug:2.0.0:30305. * com.shuyu.video.activity.PlayActivity has leaked: * GC ROOT static com.shuyu.video.MyApplication.mApplication * references com.shuyu.video.MyApplication.mLoadedApk * references android.app.LoadedApk.mReceivers * references android.util.ArrayMap.mArray * references array java.lang.Object[].[3] * references android.util.ArrayMap.mArray * references array java.lang.Object[].[2] * references android.media.MediaPlayer$ProxyReceiver.this$0 * references android.media.MediaPlayer.mProxyContext * leaks com.shuyu.video.activity.PlayActivity instance
可以看到,这个工具很强大很方便,直接指出了内存泄漏的地方,上面写的很清楚,倒数第二行说明了Mediaplayer存在一个代理引用,导致了PlayActivity无法回收,造成内存泄漏。
按理说,既然工具已经这么详细的说明了内存泄漏出现问题的地方,问题应该很好解决,但是,我查看了我的代码,mediaplayer容易出现内存泄漏的地方无非就是在和Activity进行生命周期的时候,需要自己进行释放资源,不然会造成内存泄漏。
附上我的关键代码吧:
@Override protected void onDestroy() { super.onDestroy(); ReleasePlayer(); } /** * 释放播放器资源 */ private void ReleasePlayer() { if (player != null) { player.stop(); player.release(); player = null; } }
可以看到我重写了Activity的生命周期,在OnDestroy方法中释放了Mediaplayer的资源,释放Mediaplayer的资源的方法也是网络上常用的释放Meidplayer的步骤。但是问题来了,这样怎么会造成内存泄漏哪?
最后,还是老外厉害啊,在stackoverflow上找到一篇文章,问题一模一样,原文链接
大概意思是,他查看了Mediaplayer的源码,发现存在一个引用,应该回收,但是在release方法中,并没有没处理,只有在reset方法中,这个引用才被消除。
所以结论来了:释放资源的正确方式:
/** * 释放播放器资源 */ private void ReleasePlayer() { if (player != null) { player.stop(); //关键语句 player.reset(); player.release(); player = null; } }
具体到源码,是哪一个没有回收,大概看了一下
Mediaplayer的release源码:
public void release() { baseRelease(); stayAwake(false); updateSurfaceScreenOn(); mOnPreparedListener = null; mOnBufferingUpdateListener = null; mOnCompletionListener = null; mOnSeekCompleteListener = null; mOnErrorListener = null; mOnInfoListener = null; mOnVideoSizeChangedListener = null; mOnTimedTextListener = null; if (mTimeProvider != null) { mTimeProvider.close(); mTimeProvider = null; } mOnSubtitleDataListener = null; _release(); }
reset的源码:
public void reset() { mSelectedSubtitleTrackIndex = -1; synchronized(mOpenSubtitleSources) { for (final InputStream is: mOpenSubtitleSources) { try { is.close(); } catch (IOException e) { } } mOpenSubtitleSources.clear(); } if (mSubtitleController != null) { mSubtitleController.reset(); } if (mTimeProvider != null) { mTimeProvider.close(); mTimeProvider = null; } stayAwake(false); _reset(); // make sure none of the listeners get called anymore if (mEventHandler != null) { mEventHandler.removeCallbacksAndMessages(null); } synchronized (mIndexTrackPairs) { mIndexTrackPairs.clear(); mInbandTrackIndices.clear(); }; }
我查了reset中的对象,发现mSubtitleController 这个对象在release方法中没有被处理,只在reset方法中被reset了,并且mSubtitleController 的构造方法会存在context对象,我猜应该就是这个对象,导致内存泄漏这个问题存在吧
mSubtitleController = new SubtitleController(context, mTimeProvider, MediaPlayer.this);
问题的正确与否,具体源码原理和原因待求大神解释。
相关文章推荐
- Intel UPNP lib的一个内存资源泄漏问题
- redis,java释放资源正确方式,防止redis因resource的异常
- goto语句可释放资源避免内存泄漏
- 限时免费 | 用正确的方式,三天搞定Mono堆内存泄漏!
- 调用Excel导出文件的两种方式,主要解决了资源释放的问题。
- cocos2dx中加载图片资源的方法,和从内存中获取已经加载的图片资源的方法 以及释放问题
- MVP中存在的内存泄漏问题
- 线程退出的几种方式和资源回收【线程编程中避免内存泄漏】
- Android使用多进程方式,解决Webview内存难释放的问题
- 在IE下的JS编程中,以下的编程方式都会造成即使关闭IE也无法释放内存的问题
- 虚析构函数-父子类释放内存泄漏问题
- 问题:为什么本例中c++析构函数不能正确释放内存及析构
- 浅谈C#托管程序中的资源释放问题
- Excel在.Net 环境下Web方式下驻留内存问题的解决
- JS中关于对内存的释放问题[待续]
- 关于Dot.net资源释放问题.
- 理解并解决IE的内存泄漏方式[翻译]
- Excel在.Net 环境下Web方式下驻留内存问题的解决
- Rails存在二级域,静态资源浏览器cache问题(javascripts,images,stylesheet)
- 刚注册,问个问题,在asp.net里有个xml文档以MemoryStream存在资源文件中,现在我如何把他读出来,还原成xml文档。