在c++中,变量作用域与生命周期相关的重要概念有堆、栈、静态数据区等,而在java以及as3中,由于是由虚拟机来完成内存的分配以及释放,因此对于c++编程人员来说,一方面可能以为以前调试时一大堆memory leak的问题不会存在,一方面可能又害怕java以及as3的gc(garbage collector)有没有c中手工的delete管用。
的确,gc并不是万能,我很头疼,从前几篇文章中可以看出gc的不足之处,因为出现bug后,c++编程人员知道肯定是new了没有delete,慢慢查或者借助相关工具如bounds checker等总是可以解决的,而在as3中可能会有些昏头转向。
转入正题
c++中变量作用域与as3中类似,除了as3中有一个hoisting机制会将某函数内部声明的所有局部变量全部提升到最开始,因此,如果在函数内部有两个for,在c中可以for(int i=0;;){} for(int i=0;;){},而在as3中如果for(var i:int=0;;){} for(var i:int=0;;){},则会报Warning: 3596: 变量定义重复,一开始我是被蒙了好多回
c++的变量生命周期跟变量存放位置有关,在栈上,则出栈即可视为被清空(实质等下一次覆盖这块内存区域);在堆上,则直道显示delete才可视为清空。
而as3中没有堆栈的概念,我们姑且认为所有的变量内存都统一放到某处,只不过各个变量有不同的作用域,那么到底什么时候变量对应的内存区域被清空呢?这就是gc老大人的责任了,gc老大人的怪脾气以及工作机制在as3中的资源管理与GC中有描述,一旦gc根据其运行机制认为某变量可以被清空,即清空之。
一个很重要的问题是,对于c++编程人员,可能以为在函数内部定义的“栈”上局部变量,出这个函数这个变量就会被清空!错,千万不能用这种思维,
搞的不好这个局部变量对应的内存将一直存在!!
譬如
function cFTas():void
{
var tmp:loader = new URLLoader(new URLRequest("http://www.asarea.me"));
tmp.addEventListener(ProgressEvent.PROGRESS, onloading);)
}
如果是按照c++的思维方式,tmp出cFTas就该喀了,那么tmp的事件监听就无从说起了。
我的理解,变量在离开作用域时,仅仅相当把该变量对应的内存空间的引用减少了1个
那么是谁对tmp有引用呢?谁妨碍了gc对tmp的清理呢?
一种可能是as内部的事件流机制有关,对于内部定义的一些事件,它的dispatch是何时何地怎么触发的都不得而知,肯定这个机制里面为了保证某些事件能够正确触发保留了对tmp的引用!
ps:奇怪的是,除了loader之类的流加载相关,如果是其他事件,居然出了这个函数,遇到下一个gc就会清空tmp,真是搞不懂啊,测试例子,感谢gene,单击stage会发现enterframe消失了,而loading和complete依然存在!
08.7.24加:奇怪,今天发现filereference如果定义在某个函数内部,然后在函数内部对它加各种事件,发现根本不起作用,说明这个fr出了这个函数就被喀掉了!如果把fr声明在外(也就是在外部有一个引用),而在函数内部new,结果又是可以的!而loader之类的之所以可以在函数内部定义,说明跟flash自身机制有关,在别处有对loader的引用了!
package
{
import flash.net.*;
import flash.display.Sprite;
import flash.events.*;
public class test extends Sprite
{
public function test()
{
var tmp:Sprite = new Sprite();
tmp.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
stage.addEventListener(MouseEvent.CLICK, gc);
var tmp2:URLLoader = new URLLoader(new URLRequest("http://www.yzsxwj.cn/molihua.rm"));
tmp2.addEventListener(ProgressEvent.PROGRESS, onloading);
tmp2.addEventListener(Event.COMPLETE, oncomplete);
}
private function enterFrameHandler(evt:Event):void
{
trace("enterframe");
}
private function oncomplete(event:Event):void
{
trace("completed");
}
private function onloading(evt:ProgressEvent):void
{
trace("onloading");
trace(evt.target);//.close();
}
private function gc(event:Event):void
{
try
{
new LocalConnection().connect("gc");
new LocalConnection().connect("gc");
}
catch (error:Error)
{
}
}
}
}