第九区-Jquery超级群

 找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 583|回复: 9

as3中计时器,setInterval,settimeout [复制链接]

Rank: 7Rank: 7Rank: 7

发表于 2011-7-11 00:21:22 |显示全部楼层

1. 官方说法

  无限次Timer可能会引起内存泄露,有限次Timer不会引起内存泄露

2. 实际情况(见测试用例)

  a)无限次Timer

    i.Timer在运行中且注册了TimerEvent.Timer事件侦听器,则侦听器对象本身不会被回收

    ii.Timer没有调用start()或者start后调用了stop(),侦听器对象会被垃圾回收

    iii.Timer调用了start(),但是没有对Timer注册事件侦听器或者事件侦听器被移除,不存在对侦听器垃圾回收问题

  b)有限次Timer

    i.Timer在运行中且对Timer注册了事件侦听器,则侦听器对象不会被回收

    ii.Timer调用了stop(),侦听器对象会被回收

    iii.Timer在运行了指定的repeat次数后,侦听器对象会被回收

3.结论

  Timer在运行中且注册了事件侦听器(一般用Timer,肯定会注册事件侦听器),侦听器对象不会被回收;

  由于有限次Timer迟早有结束的那一刻,所以有限次Timer一般不会造成内存泄露,但是可能会造成侦听器对象延迟释放;

  而无限次Timer则可能引起内存泄露,在一个对象释放后,如果对象内部的Timer没有停止或者没有移除事件侦听器,则对象永远不会被释放

4.好的习惯

  a)能用有限次Timer的情况,不要用无限次Timer

  b)无论是有限次Timer还是无限次Timer,在不再需要Timer时显式地调用Timer.stop(),或者移动事件侦听器(removeEventListener),并且建议两项工作都做。

5.测试用例及说明

  测试一中,在文档类中创建了一个TestTimer(test),注意这是一个局部变量。在TestTimer构造函数中,创建了一个每100毫秒触发一次的无限次Timer,并添加相应的侦听器,最后调用Timer.start()启动Timer,这时虽然程序中没有任何对TestTimer的引用,运行GC可以发现TestTimer对象不会被销毁;


  在测试二中,与测试一唯一不同的地方在于没有对timer添加事件侦听器,即少了timer.addEventListener(TimerEvent.TIMER, handleTimer),在profile中运行gc,发现testTimer的实例由1变为0,说明这种情况不会造成内存泄露;


  在测试三中,与测试二的不同在于,添加了事件侦听器,但是没有调用timer.start(),这时发现结果与测试二相同;针对测试三,可以测试另一种情况,在构造函数中调用timer.start(),但是在handleTimer中调用timer.stop()或者removeEventListner(TimerEvent.TIMER, handleTimer),测试结果与测试二相同;


  在测试四中,指定了一个执行200次的Timer(new Timer(100,200)),在Timer执行结束前,无法回收TestTimer实例,在执行完毕后可以正常回收,说明侦听器是否能被gc,是完全依赖于Timer是否在运行中,对于无限次Timer,如果不调用stop(),侦听器则不能被回收;




       public function Test(){
           var test:TestTimer = new TestTimer();
       }

}

public class TestTimer {

       private var timer:Timer;

       public function TestTimer() {
           timer = new Timer(100);
           timer.addEventListener(TimerEvent.TIMER, handleTimer);
           timer.start();
       }

       private function handleTimer (event:TimerEvent):void {
           trace(“timer”);
       }

}

setInterval

     如果不调用clearIntervalsetInterval调用的函数所在对象永远不会被回收,这是显而易见的,有怀疑精神的童鞋可以自己去做测试,就不写测试代码了;如果怀疑这个的话,建议也去测试一下,as(1+1)==2是不是返回trueo(_)o~~~哈哈!!

setTimeout


  1, 如果不调用clearTimeout,setTimeout引用的对象永远不会被回收,无论timeoutHandler是否已经执行,clearTimeout的作用不仅仅是中断未执行的timeoutHandler,更重要的是,如果不调用clearTimeout,声明timeoutHandler的对象不会被gc


  2, 测试如下代码,发现gc时,TestTimeOut的实例能够正常释放;


  3, 如果在下面的代码块的timeoutHandler中不调用clearTimeout(timeoutId),虽然此时timeoutHandler已经执行过,TestTimeOut对象在gc执行时仍然不会被回收;


  4, 关于setTimeout,多说一句, setTimeout其功能相当于只执行一次的Timer,而Timer执行一次后,无论是否stop()或者removeEventListener,其事件侦听对象都可以被正常gc;个人觉得这应该也算是设计上的失败,我一直以为clearTimeout只是用来在timeoutHandler执行之前用来取消setTimeout的;


  而且其中文帮助文档是这样说的(如果是翻译出错,算我倒霉):


  如果打算使用 clearTimeout() 方法取消 setTimeout() 调用,请确保将 setTimeout() 调用分配给一个变量(clearTimeout() 函数稍后将引用该变量)。如果不通过调用 clearTimeout() 函数取消 setTimeout() 调用,则不会将包含设置的超时 closure 函数的对象作为垃圾回收。


  如果只看前半句,我绝对不会想到这个还会影响到gc,小小地钻一下文字牛角尖:如果我不打算取消本次setTimeout()调用,那么是不是也就不必要记住tiemeoutId,那么也就无从调用clearTimeout了;

  后半句,个人认为是有歧义的(当然还是可能是翻译出了差错),而且我想了很久,这段话连起来读,第二种理解也符合一些:


  理解一:如果不调用clearTimeout,那么包含超时closure函数的对象永远也无法垃圾回收(无论超时回调closure函数是否已经执行),这个和测试结论一致,也是正确的理解;


  理解二:如果不调用clearTimeout函数,在设置的超时closure函数在执行前,包含该函数的对象不能作为垃圾回收;


  假设设置的超时closure函数所在对象没有其他引用,或者closure只是在主函数内部定义的一个局部函数, setTimeout调用执行前的确是不应该回收的,这样第二种理解也可以自圆其说。




       public function Test(){
           var test:TestTimeOut = new TestTimeOut ();
       }

}

public class TestTimeOut {

       private var timeoutId:int;

       public function TestTimeOut () {
           timeoutId = setTimeout(timeOutHandler);
       }

       private function timeOutHandler ():void {
           clearTimeout(timeoutId);
       }










Rank: 7Rank: 7Rank: 7

发表于 2011-7-12 11:00:59 |显示全部楼层
代码歪啦。
没有clear就不会被回收?
那时钟的功能该怎么写才能成功GC?
时钟是一直都在跳的吧?

不知道浏览器中的JavaScript是什么情况——怎么看GC?
不积跬步无以至千里
不积小流无以成江海

阿良的小站

使用道具 举报

Rank: 7Rank: 7Rank: 7

发表于 2011-7-12 13:15:29 |显示全部楼层
阿良 发表于 2011-7-12 11:00
代码歪啦。
没有clear就不会被回收?
那时钟的功能该怎么写才能成功GC?

js也是一样,。。。。每次都要回收的。、、、、

使用道具 举报

Rank: 7Rank: 7Rank: 7

发表于 2011-7-12 13:20:00 |显示全部楼层
king 发表于 2011-7-12 13:15
js也是一样,。。。。每次都要回收的。、、、、

你的意思是,每次都要调用clearXXX?
不积跬步无以至千里
不积小流无以成江海

阿良的小站

使用道具 举报

Rank: 7Rank: 7Rank: 7

发表于 2011-7-12 14:53:14 |显示全部楼层
阿良 发表于 2011-7-12 13:20
你的意思是,每次都要调用clearXXX?

嗯 是啊。。。。你不知道他不回收吗。。。。
var scrtime;

         $("#con").hover(function(){

                clearInterval(scrtime);

        },function(){

        scrtime = setInterval(function(){

                var $ul = $("#con ul");

                var liHeight = $ul.find("li:last").height();

                $ul.animate({marginTop : liHeight+40 +"px"},1000,function(){

                $ul.find("li:last").prependTo($ul)

                $ul.find("li:first").hide();

                $ul.css({marginTop:0});

                $ul.find("li:first").fadeIn(1000);

                });      

        },3000);

        }).trigger("mouseleave");

使用道具 举报

Rank: 7Rank: 7Rank: 7

发表于 2011-7-12 15:11:03 |显示全部楼层
真可怕
不积跬步无以至千里
不积小流无以成江海

阿良的小站

使用道具 举报

Rank: 7Rank: 7Rank: 7

发表于 2011-7-12 15:11:59 |显示全部楼层
发错代码了。。。。日。。。。。

使用道具 举报

Rank: 7Rank: 7Rank: 7

发表于 2011-7-12 15:12:48 |显示全部楼层
应该是setTimeout后把值传递给一个变量 然后 当在执行看是否有变量 有就clear 然后在执行,。。。。。手忙脚乱了

使用道具 举报

Rank: 7Rank: 7Rank: 7

发表于 2011-7-13 16:53:51 |显示全部楼层
拿东西 灌水

使用道具 举报

Rank: 7Rank: 7Rank: 7

发表于 2011-7-13 17:04:53 |显示全部楼层
学习. 学习. 学习. 学习. 学习. 学习.

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

Archiver|第九区-Jquery超级群    点击这里加入此群 点击这里加入此群

GMT+8, 2012-2-8 09:29 , Processed in 0.071018 second(s), 15 queries .

Powered by Discuz! X2

© 2001-2011 Comsenz Inc.

回顶部