51Testing软件测试论坛

 找回密码
 (注-册)加入51Testing

QQ登录

只需一步,快速开始

微信登录,快人一步

手机号码,快捷登录

查看: 3525|回复: 5
打印 上一主题 下一主题

求网页游戏中 各种可能造成内存泄露的情况~(flash)

[复制链接]

该用户从未签到

跳转到指定楼层
1#
发表于 2012-11-15 13:23:43 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
求大家把自己遇到过的内存泄露情况告诉我一下~
Thanks~
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏
回复

使用道具 举报

  • TA的每日心情
    无聊
    昨天 09:05
  • 签到天数: 1050 天

    连续签到: 1 天

    [LV.10]测试总司令

    2#
    发表于 2012-11-15 13:28:28 | 只看该作者
    什么是内存泄露

      内存泄露是指一块被分配的内存既不能使用,又不能回收,直到浏览器进程结束。在C++中,因为是手动管理内存,内存泄露是经常出现的事情。而现在流行的C#和Java等语言采用了自动垃圾回收方法管理内存,正常使用的情况下几乎不会发生内存泄露。浏览器中也是采用自动垃圾回收方法管理内存,但由于浏览器垃圾回收方法有bug,会产生内存泄露。

      内存泄露Quick View

      不同的浏览器中存在各种内存泄露方式,目前发现的主要是这样几种:

      1.    循环引用

      已经确认存在泄漏的浏览器:IE6.0 FF2.0

      含有DOM对象的循环引用将导致大部分当前主流浏览器内存泄露 这里有两个简单的概念

      引用:a.属性=b,a就引用了b

      循环引用:简单来说假如a引用了b,b又引用了a,a和b就构成了循环引用。

      a和b循环引用:

    var a=new Object;
    var b=new Object;
    a.r=b;
    b.r=a;

      a循环引用自己:

    var a=new Object;
    a.r=a;

      循环引用很常见且大部分情况下是无害的,但当参与循环引用的对象中有DOM对象或者ActiveX对象时,循环引用将导致内存泄露。我们把例子中的任何一个new Object替换成document.getElementById或者document.createElement就会发生内存泄露了。

      尽管这看起来非常容易理解,但是因为有closure的参与而使事情变得复杂,有些closure导致的循环引用很难被察觉。下面是一个非常常见的动态绑定事件:

    function bindEvent()
    {
      var obj=document.createElement("XXX");
      obj.onclick=function(){
        //Even if it's a empty function
      }
    }
    这个bindEvent执行时100%会发生内存泄露,Someone 可能会问,哪里出现了循环引用? 关于closure和scope chain参与的循环引用比较复杂,此处暂不深入讨论。有一个简单的判断方式:函数将间接引用所有它能访问的对象。obj.onclick这个函数中 可以访问外部的变量obj 所以他引用了obj,而obj又引用了它,因此这个事件绑定将会造成内存泄露。在IBM的文章中介绍了2种方式解决类似的问题一个是obj=null,另一个是把onclick的函数写在bindEvent外,重复人家的我就不说了。简单贴下代码:
    function bindEvent()
    {
      var obj=document.createElement("XXX");
      obj.onclick=onclickHandler;
    }
    function onclickHandler(){
      //do something
    }
      
    function bindEvent()
    {
      var obj=document.createElement("XXX");
      obj.onclick=function(){
        //Even if it's a empty function
      }
      obj=null;
    }

      这两个方法都打断了循环引用,可以解决问题,但是似乎对代码表达能力造成了一定破坏,假设有这么一个问题:

    function bindEvent()
    {
      var obj=document.createElement("XXX");
      var var0="OOXX";//Here is a variable
      obj.onclick=function(){
        alert(var0);//I want to visit var2 here!
      }
      return obj;//bindEvent must return obj!
    }

      好了 这下两种办法都不行了,假如我把函数写外面去,var0肯定访问不了,假如我把obj弄成null,还怎么return它呢?这并不是空想的需要,这实际上是一个用JS定制DOM控件的简单抽象:创建DOM元素、设置私有属性、绑定事件。所以,我们必须update一下两个方法。首先,方法1,为了让函数能访问某些变量,我们可以通过一个Builder函数来订制onclick的外部闭包:

    function bindEvent()
    {
      var obj=document.createElement("XXX");
      var var0="OOXX";//Here is a variable
      obj.onclick= onclickBuilder(var0);//想访问谁就把谁传进去!!
      return obj;//bindEvent must return obj!
    }
    function onclickBuilder(var0)//这里跟上面对应上就行了 最好参数名字也对应上
    {
      return function(){
        alert(var0);
      }
    }
    第二个办法,这个来自51js的chpn同学,让obj=null在return 之后执行!!

    function bindEvent()
    {
      try{
        var obj=document.createElement("XXX");
        var var0="OOXX";//Here is a variable
        obj.onclick=function(){
          alert(var0);//I want to visit var2 here!
        }
        return obj;//bindEvent must return obj!
      } finally {
        obj=null;
      }
    }

      2.    某些DOM操作

      这是IE系列的特有问题 简单的来说就是在向不在DOM树上的DOM元素appendChild,可能会发生内存泄露(只是可能,具体原因不明,似乎十分复杂,下面例子中去掉onClick也可以避免泄露)。所以appendChild的顺序可能影响内存泄露,来自微软的例子:

    </html>
      <head>
        <script language="JScript">
        function LeakMemory()
        {
          var hostElement = document.getElementById("hostElement");
          // Do it a lot, look at Task Manager for memory response
          for(i = 0; i < 5000; i++)
          {
            var parentDiv =
              document.createElement("<div >");
            var childDiv =
              document.createElement("<div >");
            // This will leak a temporary object
            parentDiv.appendChild(childDiv);
            hostElement.appendChild(parentDiv);
            hostElement.removeChild(parentDiv);
            parentDiv.removeChild(childDiv);
            parentDiv = null;
            childDiv = null;
          }
          hostElement = null;
        }
      
        function CleanMemory()
        {
          var hostElement = document.getElementById("hostElement");
          // Do it a lot, look at Task Manager for memory response
          for(i = 0; i < 5000; i++)
          {
            var parentDiv =
              document.createElement("<div >");
            var childDiv =
              document.createElement("<div >");
            // Changing the order is important, this won't leak
            hostElement.appendChild(parentDiv);
            parentDiv.appendChild(childDiv);
            hostElement.removeChild(parentDiv);
            parentDiv.removeChild(childDiv);
            parentDiv = null;
            childDiv = null;
          }
          hostElement = null;
        }
        </script>
      </head>
      <body>
        <button >Memory Leaking Insert</button>
        <button >Clean Insert</button>
        <div id="hostElement"></div>
      </body>
    </html>
    而在IE7中,貌似为了改善内存泄露,IE7采用了极端的解决方案:离开页面时回收所有DOM树上的元素,其它一概不管。但是这不仅没起到任何作用,反而使问题变得更加复杂。对这类问题,除了自觉一点绕开这些恶心的东西,多用innerHTML这种无用的建议之外。我想可以通过覆盖document.createElement来略为改善:

      首先我们定义一个看不见的元素当作垃圾箱,所有新创建的元素都扔进垃圾箱里,这样保证了所有DOM元素都在DOM树上,IE7就可以正确回收了,另一方面也能避免所谓的"appendChild顺序不对导致内存泄露"。

    function MemoryFix(){
      var garbageBox=document.createElement("div");
      garbageBox.style.display="none";
      document.body.appendChild(garbageBox);
      var createElement=document.createElement;
      document.createElement=function(){
        var obj=Function.prototype.apply.apply(createElement,[document,arguments]);
        garbageBox.appendChild(obj);
        return obj;
      }
    }

      3.    自动类型装箱转换

      别不相信,下面的代码在ie系列中会导致内存泄露

    var s=”lalala”;
    alert(s.length);

      s本身是一个string而非object,它没有length属性,所以当访问length时,JS引擎会自动创建一个临时String对象封装s,而这个对象一定会泄露。

      这个bug匪夷所思,所幸解决起来相当容易,记得所有值类型做.运算之前先显式转换一下:

    var s="lalala";
    alert(new String(s).length);
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    无聊
    昨天 09:05
  • 签到天数: 1050 天

    连续签到: 1 天

    [LV.10]测试总司令

    3#
    发表于 2012-11-15 13:28:49 | 只看该作者
    加上点解释~~
    回复 支持 反对

    使用道具 举报

  • TA的每日心情

    2019-12-27 13:32
  • 签到天数: 15 天

    连续签到: 1 天

    [LV.4]测试营长

    4#
    发表于 2012-11-20 14:35:57 | 只看该作者
    影子 晚上出来吃饭不
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    5#
     楼主| 发表于 2012-11-21 15:30:13 | 只看该作者
    回复 4# jiazurongyu


        昨天我没在公司啊~悲剧 你没回去吧? 没回去晚上吃饭呗~
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    擦汗
    2016-3-16 15:27
  • 签到天数: 25 天

    连续签到: 1 天

    [LV.4]测试营长

    6#
    发表于 2012-12-24 17:53:26 | 只看该作者
    先学习了,谢谢2楼分享
    回复 支持 反对

    使用道具 举报

    本版积分规则

    关闭

    站长推荐上一条 /1 下一条

    小黑屋|手机版|Archiver|51Testing软件测试网 ( 沪ICP备05003035号 关于我们

    GMT+8, 2024-11-22 04:02 , Processed in 0.064999 second(s), 27 queries .

    Powered by Discuz! X3.2

    © 2001-2024 Comsenz Inc.

    快速回复 返回顶部 返回列表