Android WebView Memory Leak WebView内存泄漏

在此次开发过程当中,须要用到webview展现一些界面,可是加载的页面若是有不少图片就会发现内存占用暴涨,而且在退出该界面后,即便在包含该webview的Activity的destroy()方法中,使用webview.destroy();webview=null;对内存占回收用仍是没有任何效果。有人说,一旦在你的xml布局中引用了webview甚至没有使用过,都会阻碍从新进入Application以后对内存的gc。包括使用MapView有时一会引起OOM,几经周折在网上看到各类解决办法,在这里跟你们分享一下。可是到目前为止尚未找到根本的解决办法,网上也有说是sdk的bug。可是无论怎么样,咱们仍是须要使用的。java

要使用WebView不形成内存泄漏,首先应该作的就是不能在xml中定义webview节点,而是在须要的时候动态生成。即:能够在使用WebView的地方放置一个LinearLayout相似ViewGroup的节点,而后在要使用WebView的时候,动态生成即:android

?
1
2
3
WebView      mWebView = new WebView(getApplicationgContext());
LinearLayout mll      = findViewById(R.id.xxx);
mll.addView(mWebView);
,  而后必定要在onDestroy()方法中显式的调用
?
1
2
3
4
5
protected void onDestroy() {
      super .onDestroy();
       mWebView.removeAllViews();
       mWebView.destroy()
}
;注意:  new   WebView(getApplicationgContext())  ; 必须传入ApplicationContext若是传入Activity的Context的话,对内存的引用会一直被保持着。有人用这个方法解决了当Activity被消除后依然保持引用的问题。可是你会发现,若是你须要在WebView中打开连接或者你打开的页面带有flash,得到你的WebView想弹出一个dialog,都会致使从ApplicationContext到ActivityContext的强制类型转换错误,从而致使你应用崩溃。这是由于在加载flash的时候,系统会首先把你的WebView做为父控件,而后在该控件上绘制flash,他想找一个Activity的Context来绘制他,可是你传入的是ApplicationContext。后果,你能够晓得了哈。


因而大牛们就Activity销毁后还保持引用这个问题,提供了另外一种解决办法:既然你不能给我删除引用,那么我就本身来吧。因而下面的这种方法诞生了:git

(做者说这个方法是依赖android.webkit implementation有可能在最近的版本中失败github

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public void setConfigCallback(WindowManager windowManager) {
     try {
         Field field = WebView. class .getDeclaredField( "mWebViewCore" );
         field = field.getType().getDeclaredField( "mBrowserFrame" );
         field = field.getType().getDeclaredField( "sConfigCallback" );
         field.setAccessible( true );
         Object configCallback = field.get( null );
 
         if ( null == configCallback) {
             return ;
         }
 
         field = field.getType().getDeclaredField( "mWindowManager" );
         field.setAccessible( true );
         field.set(configCallback, windowManager);
     } catch (Exception e) {
     }
}
而后在Activity中调用上面的方法:
?
1
2
3
4
5
6
7
8
9
public void onCreate(Bundle savedInstanceState) {
     super .onCreate(savedInstanceState);
     setConfigCallback((WindowManager)getApplicationContext().getSystemService(Context.WINDOW_SERVICE));
}
 
public void onDestroy() {
     setConfigCallback( null );
     super .onDestroy();
}

该反射方法在个人实验中(2.3.6)确实有些用处,在应用内存占用到70M左右的时候会明显释放到50M或者60M而后的释放就有些缓慢,其实就是看不出来了。以前在没使用该方法的时候可能达到120M。web

可是!!!咱们的应用要求占用内存更低啊,这肿么拌?凉拌么?No。在各类纠结以后,终于找到了终极解决办法!!!该办法适用于咱们的需求,在退出WebView的界面以后,迅速回收内存。要问这个方法是什么,不要9999,不要8999,只要你仔细看好下面一句话:那就是为加载WebView的界面开启新进程,在该页面退出以后关闭这个进程。app

这一点说了以后,你懂了吧?
可是在这个其中,杀死本身进程的时候又遇到了问题,网上介绍的各类方法都很差使,
killBackgroundProcesses(getPackageName());各类很差用,最后使用System.exit(0);直接退出虚拟机(Android为每个进程建立一个虚拟机的)。这个确定不用纠结了,一旦退出,内存里面释放。听涛哥说QQ也是这么作。ide


最后英雄要问出处,附上大牛解说引发该问题的出处布局

这个泄漏出如今external/webkit/Source/WebKit/android/WebCoreSupport/UrlInterceptResponse.cpp.中。具体我本身真心没有深刻研究。你们有兴趣的话,能够看看哈。ui

--- a/Source/WebKit/android/WebCoreSupport/UrlInterceptResponse.cpp +++ b/Source/WebKit/android/WebCoreSupport/UrlInterceptResponse.cpp @@ -63,10 +63,10 @@ public:          JNIEnv* env = JSC::Bindings::getJNIEnv();          // Initialize our read buffer to the capacity of out.          if (!m_buffer) { -            m_buffer = env->NewByteArray(out->capacity()); -            m_buffer = (jbyteArray) env->NewGlobalRef(m_buffer); +            ScopedLocalRef<jbyteArray> buffer_local(env, env->NewByteArray(out->capacity())); +            m_buffer = static_cast<jbyteArray>(env->NewGlobalRef(buffer_local.get()));          }          int size = (int) env->CallIntMethod(m_inputStream, m_read, m_buffer);          if (checkException(env) || size < 0)              return;          // Copy from m_buffer to out.

并且从这里https://github.com/android/platform_external_webkit/commit/1e3e46a731730c02d916ea805ec4b20191509282这个bug的解决状态。spa

还有一个问题要说的,也是在WebView使用的时候出现的问题:WebView中包含一个ZoomButtonsController,当使用web.getSettings().setBuiltInZoomControls(true);启用该设置后,用户一旦触摸屏幕,就会出现缩放控制图标。这个图标过上几秒会自动消失,但在3.0系统以上上,若是图标自动消失前退出当前Activity的话,就会发生ZoomButton找不到依附的Window而形成程序崩溃,解决办法很简单就是在Activity的ondestory方法中调用web.setVisibility(View.GONE);方法,手动将其隐藏,就不会崩溃了。在3.0一下系统上不会出现该崩溃问题,真是各类崩溃,防不胜防啊!

最后还有内存泄漏的一些个建议:

In summary, to avoid context-related memory leaks, remember the following:

  • Do not keep long-lived references to a context-activity (a reference to an activity should have the same life cycle as the activity itself)
  • Try using the context-application instead of a context-activity
  • Avoid non-static inner classes in an activity if you don’t control their life cycle, use a static inner class and make a weak reference to the activity inside

And remember that a garbage collector is not an insurance against memory leaks. Last but not least, we try to make such leaks harder to make happen whenever we can.

 

 

via: http://my.oschina.net/zhibuji/blog/100580

相关文章
相关标签/搜索