问题现象

(该文章,引自零号路的私人博客,本人在浏览框架的开发过程中,用该方式,规避了内存泄露的问题。)

在Android5.1系统中,会发现App存在 WebView 泄漏情况,还比较严重。并且只是发生在 Android 5.1 系统。

GC roots 如下:

每新打开一次这个WebViewActivity,就会发生就会发生一次改Webview实例无法释放,新增一个对象。

上图中的两个 AppSearchWebView实例,就是由于打开了两次导致。

问题分析

出现了这个问题分析起来还是比较简单的,根据这个引用关系,我们可以直观的看到是由于 Appsearch(extends Application)的 mComponentCallbacks 一直在强引用AWComponentCallbacks,导致无法释放。然后AWComponentCallbacks -> AWContents > AppSearchWebView。

通过分析代码发现关键在于 AwContents 这里的 AwComponentsCallbacks 为什么没有释放。

    @Override
    public void onAttachedToWindow() {
        if (isDestroyed()) return;
        if (mIsAttachedToWindow) {
            Log.w(TAG, "onAttachedToWindow called when already attached. Ignoring");
            return;
        }

		......

        mComponentCallbacks = new AwComponentCallbacks();
        mContext.registerComponentCallbacks(mComponentCallbacks);
    }

    @Override
    public void onDetachedFromWindow() {
        if (isDestroyed()) return;
        if (!mIsAttachedToWindow) {
            Log.w(TAG, "onDetachedFromWindow called when already detached. Ignoring");
            return;
        }
		......

        if (mComponentCallbacks != null) {
            mContext.unregisterComponentCallbacks(mComponentCallbacks);
            mComponentCallbacks = null;
        }

		......
    }

看这段代码看不出来什么问题,onAttach的时候 register,detach的时候 unregister, 不会存在问题。

但是为什么呢?

难道是由于 if (isDestroyed()) return 这条return引起的?

当调用 Webview.destroy() 后 这个判断 返回true。

我们看下哪里调用了 webview.destroy()

// source from WebViewActivity

@Override
protected void onDestroy() {
    super.onDestroy();

    if (mWebView != null) {
        mWebView.destroy();
    }
}

很多应用应该都是这么做的,包括系统浏览器,在Activity destroy的时候,调用 webview的destroy。并且一直工作的很好。

通过调试发现,确实是由于此调用导致的。onDestroy 发生在 onDetach 之前。

那为什么 android 5.1 之前的代码没有问题呢?

看下代码:

	// AwContents.java

    @Override
    public void onDetachedFromWindow() {
        if (!mIsAttachedToWindow) {
            Log.w(TAG, "onDetachedFromWindow called when already detached. Ignoring");
            return;
        }

		......

        if (mComponentCallbacks != null) {
            mContext.unregisterComponentCallbacks(mComponentCallbacks);
            mComponentCallbacks = null;
        }
		......
	}

相对于 5.1 的代码少了那句 if (isDestroyed()) return;

规避方法

  • 解决方案可以:在destroy之前,把webview 从 parent 中 remove 掉,同样可以提前detach。

      protected void onDestroy() {
          if (mWebView != null) {
              ((ViewGroup) mWebView.getParent()).removeView(mWebView);
              mWebView.destroy();
              mWebView = null;
          }
          super.onDestroy();
      }

Android5.1系统WebView内存泄漏场景的更多相关文章

  1. Android内存优化14 内存泄漏常见情况5 特殊对象造成的内存泄漏 WebView内存泄漏

    WebView造成内存泄露 关于WebView的内存泄露,因为WebView在加载网页后会长期占用内存而不能被释放,因此我们在Activity销毁后要调用它的destory()方法来销毁它以释放内存. ...

  2. 安卓android WebView Memory Leak WebView内存泄漏

    Android WebView Memory Leak WebView内存泄漏 在这次开发过程中,需要用到webview展示一些界面,但是加载的页面如果有很多图片就会发现内存占用暴涨,并且在退出该界面 ...

  3. Js中常见的内存泄漏场景

    常见的内存泄漏场景 内存泄漏Memory Leak是指程序中已动态分配的堆内存由于疏忽或错误等原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果.内存泄漏并非指内 ...

  4. js的内存泄漏场景、监控以及分析

    内存泄漏 Q:什么是内存泄漏? 字面上的意思,申请的内存没有及时回收掉,被泄漏了 Q:为什么会发生内存泄漏? 虽然前端有垃圾回收机制,但当某块无用的内存,却无法被垃圾回收机制认为是垃圾时,也就发生内存 ...

  5. Android WebView Memory Leak WebView内存泄漏

    在这次开发过程中,需要用到webview展示一些界面,但是加载的页面如果有很多图片就会发现内存占用暴涨,并且在退出该界面后,即使在包含该webview的Activity的destroy()方法中,使用 ...

  6. JVisualVM 模拟一次内存泄漏场景分析

    首先贴一段内存泄漏的代码并且执行.(内存泄漏:GC回收不掉的实例对象) package com.example.demo.memoryLeakDemo; import com.example.demo ...

  7. 系统剖析Android中的内存泄漏

    [转发]作为Android开发人员,我们或多或少都听说过内存泄漏.那么何为内存泄漏,Android中的内存泄漏又是什么样子的呢,本文将简单概括的进行一些总结. 关于内存泄露的定义,我可以理解成这样 没 ...

  8. 解决Android5.0以下Dialog引起的内存泄漏

    最近项目开发中,开发人员和测试人员均反应在android5.0以下手机上LeakCanary频繁监控到内存泄漏,如下图所示,但凡用到Dialog或DialogFragment地方均出现了内存泄漏. 如 ...

  9. Android开发之漫漫长途 番外篇——内存泄漏分析与解决

    该文章是一个系列文章,是本人在Android开发的漫漫长途上的一点感想和记录,我会尽量按照先易后难的顺序进行编写该系列.该系列引用了<Android开发艺术探索>以及<深入理解And ...

随机推荐

  1. Java中的null值总结

    自我总结,有什么不对或不到位的地方,请指出,感激不尽! 目的:熟练掌握java中null值出现的情况,避免NullPointerException 代码环境准备:需要引入junit;将代码packag ...

  2. History对象和location对象

    history对象 History对象包含用户在浏览器窗口中访问过的url.不是所有浏览器都支持该对象. 属性length   返回浏览器历史列表中的URL数量. 方法:back() 加载histor ...

  3. use zlib lib to compress or decompress file

    If you want to compress or decompress file when writing C++ code,you can choose zlib library,that's ...

  4. 所不为人知的Python装饰器

    装饰器可以说是Python中非常重要的特性之一.有些人要么从没使用过装饰器,要么就是对装饰器的使用一知半解.也有些人觉得装饰器很简单:"装饰器不就是那些把函数作为参数并输出一个函数的函数&q ...

  5. MongoDB Driver 简单的CURD

    c#中我们可以使用MongoDB.Driver驱动进行对MongoDB数据库的增删改查. 首先需要在NuGet中安装驱动 安装完毕后会发现会有三个引用 其中 MongoDB.Driver和MongoD ...

  6. SpringMVC源码情操陶冶-HandlerAdapter适配器简析

    springmvc中对业务的具体处理是通过HandlerAdapter适配器操作的 HandlerAdapter接口方法 列表如下 /** * Given a handler instance, re ...

  7. bzoj 4830: [Hnoi2017]抛硬币 [范德蒙德卷积 扩展lucas]

    4830: [Hnoi2017]抛硬币 题意:A投a次硬币,B投b次硬币,a比b正面朝上次数多的方案数,模\(10^k\). \(b \le a \le b+10000 \le 10^{15}, k ...

  8. BZOJ 3456: 城市规划 [多项式求逆元 DP]

    题意: 求出n个点的简单(无重边无自环)无向连通图数目.方案数mod 1004535809(479 * 2 ^ 21 + 1)即可. n<=130000 DP求方案 g(n) n个点所有图的方案 ...

  9. 浅谈JavaScript的事件(事件类型)

    Web浏览器能够发生的事件有很多种类型,不同的事件类型有不同的事件信息.DOM3级的事件类型主要包括:UI事件,用户与页面上的元素交互时触发:焦点事件,元素获得或失去焦点触发:鼠标事件,用户通过鼠标在 ...

  10. 微信小程序项目踩过的几个坑

    一.前言 近期,开始了一段辛酸的还未开始就已经结束的"创业"(参见我的第二次创业,以梦为马,莫负韶华).大体上是开发了一款微信小程序,关于创业这件事情就不细说了,本文主要介绍一下开 ...