打印

[AS3] AS3日积月累(3) - 利用AS3的图形界面开发及资源管理攻略

as3blog.com日积月累系列全部为原创,转载请保留:http://as3blog.com/as3/as3tip-take-care-of-resource

摒弃了attachMovie之后的AS3,采用了类似DOM的操作方式。addChild、removeChild、getChildAt等方法开始成为AS3中显示(在屏幕上渲染)、操作图形的主要方法。由于AS1、AS2完全是依赖于attchMovie的思想,因此对于传统Flash开发人员来说,转变到新的addChild的确需要下一番功夫。

由于新的“DisplayObject”在内存的使用上非常“敏感”。往往由于不良的编程习惯会造成不必要的内存泄漏,因此,我们不得不比AS1、 AS2时代更加深入到内存管理了。我想,每一个Flash开发人员,包括我自己,都应该花一番功夫仔细体会“内存管理”这几个字的含义。毕竟我们学习 AS3是为了开发比AS1、2时代更加先进、高效而且内存占用小的应用程序,如果还是开发一些简单的应用,也就失去我们每一个人使用AS3的意义了。

我觉得,由于GC是Flash应用程序内存管理的核心,我应该先从AS3中的Garbage Collector(简称GC)开始说起。AS3的GC功能比AS1、2中的要强大的多。然而,强大的同时,也带来了一定程度的复杂性。但是也不至于非常复杂,我觉得比C++等传统语言要容易掌握得多。

在研究内存如何回收之前,先说一下变量的创建:
在Flash中,我们每建立一个非原生变量时(Boolean, String, Number, uint, int这些是原生变量),这个变量名只是一个reference(指向,有时候也成为“引用”)而已,而并非这个变量本身。例如:
var a:int = 5; //a就是5
var b:int = a; //b是a,也就是5
a = 4;
trace(b); // 是5,而不是4!
//改变b的值,a不发生变化。反之亦然
var c:Object = {name:”aw”, blog:”www.awflasher.com/blog”}; //c只是指向一个内部的Object,为了描述方便,称其为“O”
var d:Object = c; //d指向c,指向了同一个Object“O”
c.name = “bw”
trace(d.name); //不是aw,而是bw了
//改变c也好,改变d也罢,其实是改变了那个“O”,因此改变c的时候,d的值也就变了。因此d.name已经被改变为了“bw”。

首先,明确一点,GC会按照一定的时间周期进行内存清理(memory sweep)。因此不要因为delete掉一个object后检查System.totalMemory内存就没有反应而怀疑GC是否正常。

那么GC为什么要按照一定的时间周期进行清理呢。这还要得从GC的具体工作原理说起。

GC的两个回收体系:
1、“Reference Counting” - 引用计数器
这个体系是自从AS1时代就有的体系,它的工作原理非常简单:系统计算每一个对象被指向,或者说引用的次数。比如
var a:Object = {name:”aw”, blog:”www.awflasher.com/blog”};
这时候,这个Object(我们仍然称为“O”),有一次引用,它的引用计数器为1(来自a)。
我们再建立一个对象b,并指向到a:
var b:Object = a;
这时候“O”引用计数器变为了2(来自a、b)
我们删除一个,比如先删除b:
delete b;
这时候引用计数器为(2-1=1)1,GC不操作
再删除另外一个a:
delete a;
“O”引用计数器变为(1-1=0)0,GC出面干掉这个对象。
这套体系很轻便,CPU压力较小。但是它也有缺陷。当我们的对象内部互相引用的时候,麻烦就来了。例如:
var a:Object = {name:”aw”, description:”unknown”};
// 建立一个对象a,仍然假设内部对象为“O”,这时O的引用次数为1
var b:Object = {nameObj:a, url:”awflasher.com”};
// b引用了a,同时创建了新的内部对象“P”。这时O的引用次数为2,P为1
a.myDescription = b;
// a的myDescription属性指向到了b。这样,P的引用次数也为2了。
// 是不是有点头晕?静下来,画个图慢慢看看:)
delete a;
delete b;
两次delete操作后,O、P的引用次数都是1,它们将继续占用你的内存。“Reference Counting” 体系无能为力了。

2、“Mark Sweeping” - 标记清除法则
GC的第一种机制“Reference Counting”,在FlashPlayer8之前是GC唯一的机制。FlashPlayer6和7由于引入了复杂的OOP开发模式,尤其是7引入了类似Java、C++等强大OOP语言的语法。利用Flash设计的复杂项目越来越多。由于Flash开发人员大多不了解GC,而Java、C++的开发人员又已经习惯了强大的GC(无论是自动的还是手动的)。因此FlashPlayer6、7的内存问题开始浮现出来。
Okay,Flash Player8引入了新的“Mark Sweeping”机制。我想这也是当年Marcomedia(Adobe)基于退出Player8的原因吧!(还记得当年Flash8的介绍视频么,效率提高是一个革命性的改进)
下面就来讲述“Mark Sweeping” - 标记清除法则的工作原理。
FlashPlayer会从root开始,遍历系统的每一个变量,并对有指向的对象之间,记录一次联系。在遍历结束之后,凡是与root不相联系的对象,被FlashPlayer无情地干掉:)
Okay,回到刚才的例子,当我们delete a,并delete b之后,root与O、P就划清了界线。这时候,GC就可以进行一次肃清了。
然而,由于这种“Mark Sweeping”要遍历所有的对象,因此非常消耗资源。这也就回到了当初的问题:“GC为什么要按照一定的时间周期进行清理“ - 因为不能给CPU造成太大的负担。
我个人猜测,GC的内部清除策略应该是在某一次事件(例如delete)发生后,在CPU比较空闲、RAM分配相对合理的情况下执行的。

Okay,不要以为有了“Mark Sweeping”就万事大吉了。由于GC不会即时进行,因此你的对象会在一段时间内“阴魂不散”!对于一个追求完美的开发人员来说,这意味着它们内部的某些机制会在被删除之后继续工作:AS语句会继续执行、声音会继续播放、事件会继续触发!

KirupaForum有网友说,“All you got to do is pray the garbage collector doesn’t break down.”,确实,如果一个应用程序要运行上一个多小时,那么慢慢流逝的内存会让你的用户对你的产品失望(例如游戏)。因此我们需要有一个良好的资源管理策略。

待续……
aw 厉害啊 这么晚了 顶你
http://www.5ucai.com
无忧素材网
严重待续
我喜欢这种带有学术味道的帖子。支持aw一把。

有个错误一定要指出:
delete在AS3中用法有重大改变,不能用来删除对象,只能用在删除动态属性上。
因此,你的例子不成立,会报错:
复制内容到剪贴板
代码:
var a:Object = {name:"aw", blog:"www.awflasher.com/blog"};
var b:Object = a;
delete b;
//报错:1189: Attempt to delete the fixed property a.  Only dynamically defined properties can be deleted.
delete a;
//报错:1189: Attempt to delete the fixed property a.  Only dynamically defined properties can be deleted.
在AS3中要删除对象只能使用
复制内容到剪贴板
代码:
b= null;
a= null;
黑羽翔天◎足下八邦
欢迎来我的博客 :)
www.kingda.org  (AS3教程)

TOP

还在为头像烦恼?还在为不能关注好友动态烦忧?快来蓝色理想家园吧!
另外关于垃圾回收机制,aw介绍的是两种已经成熟的垃圾回收理论。前段时间,看了AVM代码后,我发现AVM同时采用了这两种方式,和目前其他强大的OOP语言一致。
而且还要复杂一些。
由于加入了对弱引用的支持,AVM2的垃圾回收机制更加强大。AVM中使用了GCFinalizedObject来表示要回收的对象,而其子类GCWeakRef就是用来处理弱引用对象的。

至于何时回收,机制比较复杂。我看到代码中是和堆的分配联系在一块儿的。堆的状态符合算法要求后,才开始进行垃圾回收。一种比较常见的外部表现是:可能到了程序占用一定数量的内存后,反复震荡,这个时候就是垃圾回收机制在工作了。
各位有兴趣的可以使用每隔一点时间连续不断的创建一定size的匿名位图对象,来测试垃圾回收的表现。

[ 本帖最后由 KingdaSun 于 2007-5-13 13:09 编辑 ]
黑羽翔天◎足下八邦
欢迎来我的博客 :)
www.kingda.org  (AS3教程)

TOP

好东西
没完的吧.待续

TOP

Orz....
不懂不懂....
膜拜楼上各位老大ing....

TOP

好像GC并不是按照一定的时间周期进行内存清理的。
垃圾回收是一项比较耗费资源的操作,
不到需要的时候是不会自动去执行的。

TOP

提醒:最后回贴距现在137天,请不要无意义回复

TOP