Flash应用效率优化启示录Ⅰ

比起其他语言,Flash ActionScript3的上手过程要简单许多,对于很多人我想大多都是被这一点吸引进了咱们的圈子,很快就能看到很cool的效果,很好玩。不过实现一个效果容易,想对一个不论是简单还是复杂的应用做到运行时一直保持高效率地运转就是一个比较考验Flash开发人员的事情了。
       “为什么我的应用越运行越卡?”这个问题有非常多的原因啦,我们一个个来看,对于效率优化也是一个很长的话题,这就是为什么我的标题里要写上一个一,以后想到一点加一点吧,希望对列位爱卿有所帮助,come on,let`s go! Enjoy!

●避免创建过多实例
     这个问题是很基础的一点,一般新手比较容易犯,有一些老手在不注意的时候也容易出现实例过多造成的内存溢出情况。我们一起来看一个相当简单的例子,我们想要在点击舞台时产生一个随机颜色的小球,但是舞台上一次只能存在一个小球,第二次点击舞台时,第一次点击产生的小球会消失。来看看下面这种写法:
我们需要的球类:

  1. public class Ball extends Shape
  2. {
  3.         private var _radius:Number;
  4.         
  5.         public function Ball( radius:Number = 5, color:uint = 0xff0000 )
  6.         {
  7.                 _radius = radius;
  8.                 var g:Graphics = this.graphics;
  9.                 g.clear();
  10.                 g.beginFill( color );
  11.                 g.drawCircle(0, 0, _radius);
  12.                 g.endFill();
  13.         }
  14. }
复制代码
接下来开始测试:
  1. public class OptimizeYourFlashApp extends Sprite
  2.         {
  3.                 private var ball:Ball;
  4.                 
  5.                 public function OptimizeYourFlashApp()
  6.                 {
  7.                         stage.addEventListener(MouseEvent.CLICK, onClick);        
  8.                 }
  9.                 
  10.                 private function onClick( e:MouseEvent ):void
  11.                 {
  12.                         
  13.                         if( this.numChildren > 0 )
  14.                         {
  15.                                 for(var i:int=0; i<this.numChildren; i++)
  16.                                 {
  17.                                         this.removeChildAt(i);
  18.                                         i--;
  19.                                 }
  20.                         }

  21.                         ball = new Ball(30, Math.random() * 0xffffff);

  22.                         addChild( ball );
  23.                         ball.x = mouseX;
  24.                         ball.y = mouseY;
  25.                 }
  26.         }
复制代码
很一般的做法对不对?好,让我们用Flash Builder的profile来看一下内存测试结果:
1.jpg 
我们看到Ball类的实例数instances有两百多个,这是当然的,因为每次点击后都会new一个新的Ball实例出来,这直接导致的结果就像我们上图所示,占有了47000多的内存,占全应用内存使用量的99%以上,当前内存使用量(current memory)高达65K……如此简单的一个应用就能在我点击两百次鼠标后达到65K的内存占用。
虽然把没有用的实例置为空(如 ball = null )可以消除实例释放内存,但是最好的办法还是优化你的算法!
事实上我们可以改用别的方式来避免创建太多的实例,因为我们要实现的功能是让场景里只存在一个球,而且每次点击的颜色不同,那么我们仅需每次点击后改变原先的球的颜色即可。于是我们为Ball类增加一个改变颜色的接口:
  1. class Ball extends Shape
  2. {
  3.         private var _radius:Number;
  4.         
  5.         public function Ball( radius:Number = 5, color:uint = 0xff0000 )
  6.         {
  7.                 _radius = radius;
  8.                 this.color = color;
  9.         }
  10.         
  11.         public function set color( value:uint ):void
  12.         {
  13.                 var g:Graphics = this.graphics;
  14.                 g.clear();
  15.                 g.beginFill( value );
  16.                 g.drawCircle(0, 0, _radius);
  17.                 g.endFill();
  18.         }
  19. }
复制代码
这样就不必每次都new一个实例了。在文档类里面应用起来:
  1. public class OptimizeYourFlashApp extends Sprite
  2.         {
  3.                 private var ball:Ball;
  4.                 
  5.                 public function OptimizeYourFlashApp()
  6.                 {
  7.                         stage.addEventListener(MouseEvent.CLICK, onClick);
  8.                         
  9.                 }
  10.                 
  11.                 private function onClick( e:MouseEvent ):void
  12.                 {
  13.                         
  14.                         if( this.numChildren > 0 )
  15.                         {
  16.                                 for(var i:int=0; i<this.numChildren; i++)
  17.                                 {
  18.                                         this.removeChildAt(i);
  19.                                         i--;
  20.                                 }
  21.                         }
  22.                         if(ball == null)
  23.                         {
  24.                                 ball = new Ball(30, Math.random() * 0xffffff);
  25.                         }
  26.                         else
  27.                         {
  28.                                 ball.color = Math.random() * 0xffffff;
  29.                         }
  30.                         addChild( ball );
  31.                         ball.x = mouseX;
  32.                         ball.y = mouseY;
  33.                 }
  34.         }
复制代码
最后我们在profile里看看内存使用情况:
2.jpg 
你懂的!

对于一些老鸟来说也会出现莫名其妙的内存溢出问题,有时候这种“偷袭”会让我们不知所措,此时可能只有Flash Builder的profile能告诉我们是哪个狗东西搞得鬼。我们敬爱的导师MoonSpirit在使用Tweenlite时就有过内存溢出的经验,Tweenlite是一个Flash动画补间引擎,在之前的案例里面我有提到过,它最最常用的方法是TweenLite.to()方法,我们一般都是直接使用这个静态方法,而忽略了该方法会返回一个TweenLite的实例,因此我们每次调用TweenLite.to()方法时都会新声明一个新的TweenLite实例,待实例一多就会出现内存溢出的危险,因此一个好的习惯是每次用TweenLite.to()方法后都及时把它生成的实例给干掉,我们可以使用TweenLite实例它自带的kill方法来做到:
  1. var tween:TweenLite = TweenLite.to(ball, 1, 
  2. {x:mouseX, y:mouseY, onComplete: function(){ tween.kill() } });
复制代码
这样就可以在每一次补间动画播放完毕后让to方法新生成的TweenLite实例停止播放并标记为“回收”状态,在下一次Flash Player垃圾回收阶段会回收这些无用的实例,释放内存。

●及时清理事件侦听
这也是个老生常谈的问题,很多前辈们都已经多次提到,我这里只简言带过:一个实例中若是存在事件侦听,那么该实例及时用不到它它也会占用内存,不能被垃圾回收。因此我们必须及时地移除事件侦听,保持内存不会堆积废物。被广泛使用的一种设计模式是重载addEventListener方法使每次添加事件侦听时都能把它保存到一个数组中,在该实例要下岗之时把数组中保存的事件侦听一一移除,这样就干净了……
  1. private var listeners:Array = new Array();
  2.                 
  3.                 override public function addEventListener(type:String, listener:Function, useCapture:Boolean=false, priority:int=0, useWeakReference:Boolean=false):void
  4.                 {
  5.                         super.addEventListener(type, listener, useCapture, priority, useWeakReference);
  6.                         var newListener:Object = {lType:type, lListener:listener};
  7.                         listeners.push( newListener );
  8.                 }
  9.                 
  10.                 //调用此方法以清除全部已添加了的事件侦听器
  11.                 public function clear():void
  12.                 {
  13.                         for each( var listener:Object in listeners)
  14.                         {
  15.                                 this.removeEventListener( listener.lType, listener.lListener );
  16.                         }
  17.                         listeners = [];
  18.                 }
复制代码
有的时候,我们希望一个实例中的事件侦听器长期侦听事件,但是这个事件又触发得不是很频繁(通常是一些自定义的事件),那么我们希望在事件一段时间内一直没有触发过的情况下不让这个事件侦听器妨碍垃圾回收,让FP能顺利释放该实例所在内存。这时我们可以使用事件侦听器的“弱引用”来做到在不移除事件侦听器的情况下顺利实现实例的垃圾回收。将一个事件侦听器设置为“弱引用”的方式及其简单,只需设置addEventListener的第5个参数“useWeakReference”为true即可。如下:
  1. addEventListener(MouseEvent.CLICK, onClick, false,  0, true);
复制代码
我们保持第3,4个参数为默认值,设置第五个参数为true即可设置该事件侦听为弱引用,若一个实例中存在若引用的事件侦听器那么该实例在闲置时依然会被顺利地垃圾回收并释放内存,但是事件触发时依然能够准确地侦听到事件。为事件侦听设置弱引用能够极大地缓解Flash应用的“疲劳”,它在大型Flash应用的开发中已被广泛使用。
      另外,由于事件侦听器会影响实例的垃圾回收,所以建议尽可能少地添加侦听器。在addEventListener方法中存在多个参数,我们刚才提到的“弱引用设置”是最后一个参数,那么还有两个参数是比较陌生的,这里谈谈第三个参数useCapture(使用捕获),我们知道Flash事件机制中每一个事件的触发都是从捕获阶段开始的,这个阶段是从最外层容器向内部子容器遍历以搜索事件发生者。那么我们如果在一个父容器中设置useCapture=true,那么该容器中所有子容器在发生事件时父容器都能侦听到,这样就可以避免为每个子容器添加事件侦听器:
  1. public function Test()
  2. {

  3.     for(var i:int=0; i<100; i++)
  4.    {
  5.         var child:CustomClass = new CustomClass ()//某个自定义类
  6.         addChild( child );
  7.     }
  8.     this.addEventListener( MouseEvent.CLICK, onClick, true)
  9. }

  10. private function onClick( event:Event ):void
  11. {
  12.      var c:CustomClass  = event.target as CustomClass;
  13.      trace( c );
  14. }
复制代码
另外,对于带多个动画的Flash应用,建议不要为每个动画元件中添加ENTER_FRAME或者TIMER事件侦听,而是建立一个总的时间管理者,在这个管理者中添加ENTER_FRAME或者TIMER事件侦听并在事件处理函数中对所有动画元件进行统一调度。

●避免过多运算
     AS语言的计算效率不必C语言等底层语言,我们在计算时应尽可能避免过多过频繁地计算。比如下列一个循环:
  1. for( var i:int=0; i< array.length; i++ )//arrary是一个长度很长的数组
  2. {
  3.      //do something
  4. }
复制代码
对于这个循环,每次循环开始时都会计算array的长度,如果array长度比较短还好,长度很长,循环次数很多时就会做很多冗余的计算,好的习惯是事先计算好数组的长度再开始循环:
  1. var len:int = array.length;
  2. for( var i:int=0; i< len; i++ )//arrary是一个长度很长的数组
  3. {
  4.      //do something
  5. }
复制代码
这里注意一下数组长度会改变的情况,需要动态地更改长度才行:
  1. var len:int = array.length;
  2. for( var i:int=0; i< len; i++ )//arrary是一个长度很长的数组
  3. {
  4.     arrary.pop();
  5.     len--;
  6. }
复制代码
在《动画高级教程》中的第一章:高级碰撞检测中也提到过类似问题,在做大量物体的碰撞检测时若是在每一帧都对每个对象进行遍历,让一个对象与其他对象依次进行碰撞检测的话会进行大量的运算,对于N个对象,每帧将会进行(N^2-N)/2次测试,100个对象在每一帧都会进行4950次碰撞检测,这将会拖垮CPU,因此我们必须采用一些好的算法来避免大量运算。

(转载于天地会论坛)

动物目标检测数据集 一、基础信息 数据集名称:动物目标检测数据集 图片数量: - 训练集:9,134张图片 - 验证集:1,529张图片 - 测试集:1,519张图片 总计:12,182张图片 分类类别: Bear(熊)、Cat(猫)、Cattle(牛)、Chicken(鸡)、Deer(鹿)、Dog(狗)、Elephant(大象)、Horse(马)、Monkey(猴子)、Sheep(绵羊) 标注格式: YOLO格式,包含归一化坐标的边界框和数字编码类别标签,支持目标检测模型开发。 数据特性: 涵盖俯拍视角、地面视角等多角度动物影像,适用于复杂环境下的动物识别需求。 二、适用场景 农业智能监测: 支持畜牧管理系统开发,自动识别牲畜种类并统计数量,提升养殖场管理效率。 野生动物保护: 应用于自然保护区监控系统,实时检测特定动物物种,辅助生态研究和盗猎预警。 智能养殖设备: 为自动饲喂系统、健康监测设备等提供视觉识别能力,实现精准个体识别。 教育研究工具: 适用于动物行为学研究和计算机视觉教学,提供标准化的多物种检测数据集。 遥感图像分析: 支持航拍图像中的动物种群分布分析,适用于生态调查和栖息地研究。 三、数据集优势 多物种覆盖: 包含10类常见经济动物和野生动物,覆盖陆生哺乳动物与家禽类别,满足跨场景需求。 高密度标注: 支持单图多目标检测,部分样本包含重叠目标标注,模拟真实场景下的复杂检测需求。 数据平衡性: 经分层抽样保证各类别均衡分布,避免模型训练时的类别偏差问题。 工业级适用性: 标注数据兼容YOLO系列模型框架,支持快速迁移学习和生产环境部署。 场景多样性: 包含白天/夜间、近距离/远距离、单体/群体等多种拍摄条件,增强模型鲁棒性。
数据集介绍:农场与野生动物目标检测数据集 一、基础信息 数据集名称:农场与野生动物目标检测数据集 图片规模: - 训练集:13,154张图片 - 验证集:559张图片 - 测试集:92张图片 分类类别: - Cow(牛):农场核心牲畜,包含多种姿态和场景 - Deer(鹿):涵盖野外环境中的鹿类目标 - Sheep(羊):包含不同品种的绵羊和山羊 - Waterdeer(獐):稀有野生动物目标检测样本 标注格式: YOLO格式标准标注,含精确边界框坐标和类别标签 数据特征: 包含航拍、地面拍摄等多视角数据,适用于复杂环境下的目标检测任务 二、适用场景 智慧农业系统开发: 支持畜牧数量统计、牲畜行为监测等农业自动化管理应用 野生动物保护监测: 适用于自然保护区生物多样性监测系统的开发与优化 生态研究数据库构建: 为动物分布研究提供标准化视觉数据支撑 智能畜牧管理: 赋能养殖场自动化监控系统,实现牲畜健康状态追踪 多目标检测算法验证: 提供跨物种检测基准,支持算法鲁棒性测试 三、数据集优势 多场景覆盖能力: 整合农场环境与自然场景数据,包含光照变化、遮挡等真实场景 精确标注体系: - 经专业团队双重校验的YOLO格式标注 - 边界框精准匹配动物形态特征 数据多样性突出: - 包含静态、动态多种动物状态 - 涵盖个体与群体检测场景 任务适配性强: - 可直接应用于YOLO系列模型训练 - 支持从目标检测扩展到行为分析等衍生任务 生态研究价值: 特别包含獐等稀有物种样本,助力野生动物保护AI应用开发
数据集介绍:多环境动物及人类活动目标检测数据集 一、基础信息 数据集名称:多环境动物及人类活动目标检测数据集 图片数量: - 训练集:12,599张图片 - 验证集:1,214张图片 - 测试集:607张图片 总计:14,420张图片 分类类别: - bear(熊): 森林生态系统的顶级掠食者 - bird(鸟类): 涵盖多种飞行及陆栖鸟类 - cougar(美洲狮): 山地生态关键物种 - person(人类): 自然环境与人类活动交互场景 - truck(卡车): 工业及运输场景的车辆目标 - ungulate(有蹄类动物): 包括鹿、羊等草食性哺乳动物 - wolf(狼): 群体性捕食动物代表 标注格式: YOLO格式标注,包含归一化坐标的边界框及类别标签,可直接适配YOLOv5/v7/v8等主流检测框架。 数据特性: 涵盖航拍、地面监控等多视角数据,包含昼夜不同光照条件及复杂背景场景。 二、适用场景 野生动物保护监测: 支持构建自动识别森林/草原生态系统中濒危物种的监测系统,用于种群数量统计和栖息地研究。 农业与畜牧业管理: 检测农场周边的捕食动物(如狼、美洲狮),及时预警牲畜安全风险。 智能交通系统: 识别道路周边野生动物与运输车辆,为自动驾驶系统提供碰撞预警数据支持。 生态研究数据库: 提供7类典型生物与人类活动目标的标注数据,支撑生物多样性分析与人类活动影响研究。 安防监控增强: 适用于自然保护区监控系统,同时检测可疑人员(person)与车辆(truck)的非法闯入。 三、数据集优势 多场景覆盖: 包含森林、公路、山地等多类型场景,覆盖从独居动物(cougar)到群体生物(wolf)的检测需求。 类别平衡设计: 7个类别经专业数据采样,避免长尾分布问题,包含: - 3类哺乳动物捕食者(bear/cougar/wolf) - 2类环境指示物种(bird/ung
数据集介绍:野生动物与家畜多类别目标检测数据集 数据集名称:野生动物与家畜多类别目标检测数据集 数据规模: - 训练集:8,293张图片 - 验证集:886张图片 - 测试集:445张图片 总数量:9,624张户外场景图片 分类类别: 包含31个动物与人物类别:熊、冠蓝鸦、野猪、猫、牛、郊狼、乌鸦、鹿、犬类、鸭、鹰、狐狸、山羊、鹅、刺猬、马、鼠类、负鼠、猫头鹰、猪、鸽子、豪猪、兔、浣熊、臭鼬、蛇、松鼠、火鸡、狼、花栗鼠及人类。 标注格式: YOLO格式边界框标注,支持主流目标检测框架训练,包含标准化坐标和类别ID。 数据特性: 户外场景采集,涵盖昼夜不同光照条件下的动物行为影像,包含地面视角和部分俯视角度。 1. 生态监测系统开发: 支持构建野生动物自动识别系统,应用于自然保护区生物多样性监测。 1. 农牧业智能管理: 识别家畜与潜在威胁动物(郊狼、野猪等),辅助建设智能牧场安防系统。 1. 城市野生动物管控: 检测浣熊、臭鼬等城市常见野生动物,应用于城市生态管理系统开发。 1. 智能安防系统: 支持人畜共处场景检测,适用于农场、仓库等场所的智能监控方案。 1. 学术研究支持: 为动物行为学、种群生态学研究提供标准化视觉数据支撑。 物种多样性覆盖: 包含31个动物类别,涵盖哺乳动物、鸟类、爬行类等主要动物门类,特别包含多种具有生态指示作用的物种。 场景真实性: 数据采集自真实户外环境,包含复杂背景下的动物检测样本,有效提升模型泛化能力。 专业标注体系: - 严格遵循YOLO标注标准 - 包含动物全身及局部特征标注 - 特殊标注重叠/遮挡场景 - 人类与动物交互场景标注 任务适配性: - 支持目标检测模型训练与验证 - 适用于多类别分类任务 - 兼容YOLOv5/v7/v8等主流框架 生态研究价值: 包含多个生态链关键物种(如顶级掠食者狼、郊狼),支持构建生态系统健康评估模型
多场景动物与交通工具目标检测数据集 一、基础信息 数据集名称:多场景动物与交通工具目标检测数据集 数据规模: - 训练集:12,427张 - 验证集:826张 - 测试集:392张 分类类别: - 野生动物:熊、鹿、浣熊 - 家养动物:马、猫、狗、山羊、兔子 - 鸟类:飞鸟 - 交通工具:汽车 标注格式: YOLO格式标注,包含标准化边界框坐标与类别索引,适配主流目标检测框架 二、适用场景 生态监测系统开发: 适用于自然保护区的野生动物自动监测,支持熊、鹿、浣熊等物种的实时识别与数量统计 智慧农业应用: 可用于牲畜养殖场的动物行为监控,精准识别山羊、兔子等家畜的异常活动 智能安防系统: 支持住宅区的宠物(猫/狗)与野生动物(浣熊)识别,构建入侵预警系统 自动驾驶感知: 提供道路场景中的动物(马/鹿)与汽车联合检测能力,增强自动驾驶系统的环境感知 三、数据集优势 跨领域多样性: 覆盖10个差异化物种类别,包含空中(飞鸟)、地面(汽车/动物)、树栖(浣熊)等多维度检测目标 复杂环境适配: 包含黎明景观、空中拍摄、道路环境等多场景数据,提升模型在不同光照和背景条件下的鲁棒性 标注专业性强: 采用YOLO标准化标注流程,边界框精准匹配目标形态,支持密集小目标(鸟群)检测需求 任务扩展潜力: 适用于目标检测模型训练与性能基准测试,可扩展应用于物种分类、活动模式分析等衍生任务
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值