原帖地址:http://blog.csdn.net/xingjunli/archive/2010/01/14/5186058.aspx
在RIA应用开发过程中,性能一直是我们关注的一个重点;生成swf文件的大小,内存、cpu资源消耗,事件响应等,都将影响用户在浏览或者使用过程中的体验;
这就要求我们在平时的开发过程中养成良好的编程习惯,合理使用组件,避开一些较消耗资源的因素。本文将针对这些问题展开一些讨论:
1、初始化对象时优化:
1.1、可能的话使用AS来创建你的组件/类(通常通过代码绘制和创建的实例运行效率更高(如使用graphics绘制图形))
1.2、为property分配初始化默认值:(如:<mx:TextArea text="hi" width="100" />)
1.3、连接对象:
1.3.1、将新的对象添加到已显示的列表中
1.3.2、绑定事件处理函数:<mx:Button click="goNext()" />;
1.3.3、数据绑定:<mx:label text="{city}" />;
1.3.4、监听Effect效果:<mx:label showEffect="{fade}"/>;
1.4、延迟对象创建(默认延迟实例化Flex在启动时不会构建任何子对象视图):
1.4.1、直到对象需要显示时再创建实例;
1.4.2、使用Flex中的导航容器(如According、ViewStack、TabNavigator)中内置的推迟实例化功能;
1.4.3、子ViewStack容器比自定义容器更简单高效
1.5、依次顺序创建:
1.5.1、启动过程中错开对象的创建
1.5.2、使用creationPolicy属性优化启动时间及顺序(如下:顺序依次创建)
<mx:Applicaion>
<mx:Panel width="250" heigth="100" creationPolicy="queued"> //顺序创建组件,想插队的话设置creationIndex
<mx:label text="one" />
</mx:Panel>
<mx:Panel width="250" heigth="100" creationPolicy="queued">
<mx:label text="two" />
</mx:Panel>
</mx:Applicaion>
1.5.3、谨慎使用<mx:Repeater>:
1.5.3.1、不推荐使用 <mx:Repeater>创建立重复组件
糟糕的:<mx:VBox>
<mx:Repeater id ="r" dataProvider="{arry}">
<mx:Image source="r.currentItem.url" />
</mx:Repeater>
</mx:VBox>
推荐:<mx:List dataProvider ="{arry}">
<mx:itemRenderer>
<mx:Component>
<mx:Image source="{dataObject.url}" />
</mx:Component>
</mx:itemRenderer>
</mx:List>
说明:直接创建组件放在Scroll中效率更高
2、优化你的布局和组件大小:
2.1、定义:
尽可能在初始化和创建的过程中为所有组件设置其位置和大小
<mx:Application>
<ms:HBox>
<mx:Button label="1" />
<mx:Button label="2" />
</ms:HBox>
<mx:textArea width="100%" height="100%" text="text" />
</mx:Application>
2.2、描述(尽可能多的使用绝对定位和缩放):
2.2.1、设置(需要知道所有动态设置大小,自适应都将涉及到大量的运算):从下至上(从内向外)遍历可视组件树
2.2.1.1、为类似Button 、TextArea的组件设置大小
2.2.1.2、为HBox组件设置大小
2.2.1.3、为主Applicaton设置大小
2.2.2、布局:从上至下(从外向内)遍历可视组件树:
2.2.2.1、给Application设置大小,为HBox textArea设置位置
2.2.2.2、给HBox设置大小,为Button设置位置
2.2.3、运算法则:设置属性n为数字或者对象
2.3、减少并避免容器多层嵌套:
2.3.1、尝试使用HBox 和VBox代替Grid
2.3.2、避免在Applicaton的VBox外再嵌套一个Panel
2.3.3、不要在MXML组件的根节点下嵌套一个子容器
2.3.4、推荐使用Canvas这种效率最高的容器
2.3.5、警告:一个容器通常推荐只包含一个子节点
2.4 、避免重复设置和布局:
2.4.1、场景1:当请求的图片较多时(如超过25个),建议所有图片都装载完成后再循环设置其大小和布局
2.4.2、场景2:当有多个窗体都需要请求WebService时,循环WebService响应,只改变请求窗体的大小
2.4.3、备注:将请求延迟到窗体创建完成(在 Layout完成之后),在请求和响应的过程中尽量不要使用几何图形方面的变化,尽可能错开请求或者响应的消息队列
3、优化呈现(Rendering):
3.1、重绘区域:
3.1.1、如果一个对象的属性发生了变化,哪么它的边框是“重绘区”
3.1.2、可视化“显示重绘区域”(调试播放器适用)
3.1.3、对象重叠区域的重绘
3.2、缓存位图保持原有状态(cachePolicy):
3.2.1、如果缓存位图为true,对象和它的子对象都呈现为屏幕外(内存)视图
3.2.2、如果对象重叠重绘区和对象没有改变则使用缓存位图
3.3、缓存位图是一把双刃剑:
3.3.1、如果对象缓存了位图,当对象改变时开消是昂贵的
3.3.2、如缓存了位图在应用 resize Effect /resize浏览器窗口时都会损失性能
3.3.3、建议仅在短时间内缓存位图
3.4、影响呈现(Rendering)速度的因素:
3.4.1、重设、重绘区域;建议:重构UI
3.4.2、缓存位图(帮助/损失)
3.4.3、所有矢量图重绘区;建议:简化矢量图形状、在重设大小和状态转换过程中隐藏子节点;
3.4.4、混合文本和矢量图形
3.4.5、使用剪切遮罩(如加载组合大图剪切应用小图,减少多次图片请求加载)
3.4.6、合理使用filters(如创建阴影)
3.4.7、其它后台处理过程(如建议将Effect延迟至后台处理)
4、其它优化:
4.1、移除没有使用的UI或者事件监听(或者变成弱应用):
myViewStack.removeChild(childView);
childView.removeEventListener("click",clickHandler) ;
4.2、清除没有被引用或者使用的数据:
myProperty = null;
myWebservice.getAddressBook.clear.Result();
4.3、使用样式:
4.3.1、改变和重设样式代价最昂贵:
StyleManager.styles.Button.setStyle("color",0xff0000);
4.3.2、内联样式的代价与对象的数量成正比的:
myVBox.setStyle("color",0xff0000);
4.3.3、在初始化的过程中尽早的设定样式(在initialize时而不是在createComplete时)初始化设置样式应用使用<mx:Style>标签:
<mx:Style>Button{color:#0xf0000}</mx:Style>
<mx:VBox id="myVBox" color="oxffffff"/>
4.3.4、避免使用setStyle()如确实需要,则应在实例化节点时尽早调用
4.4、使用内存分析工具(profiling tools)检测资源使用情况查找内存泄露 :
4.4.1、方法调用频繁
4.4.2、方法持续时间
4.4.3、堆栈调用
4.4.4、对象实例总数
4.4.5、对象大小
4.4.6、垃圾收集... ...
4.5、根据功能模块化动态装载(不要让用户为他可能不会用到的功能模块买单,尽管用户在首次切换时可能需要花费比较多的代价)
5、减少和压缩SWF体积
5.1、减少内置资源(如字符集,图片,视频,音频(Embeded)标签)等)的加载;使用外部文件尽量运行时载入而不是编译时嵌入
5.2、禁止调试,同时删除一些专们为记录调试环境的数据和方法
5.3、避免引入一些不必要的包和类;
5.4、使用RSL分离和缓存框架(framework.swc)以减小生成文件体积:
以下是一网络资源记下来参考:
Flex性能优化常用手法总结:
内存释放优化原则
1. 被删除对象在外部的所有引用一定要被删除干净才能被系统当成垃圾回收处理掉;
2. 父对象内部的子对象被外部其他对象引用了,会导致此子对象不会被删除,子对象不会被删除又会导致了父对象不会被删除;
3. 如果一个对象中引用了外部对象,当自己被删除或者不需要使用此引用对象时,一定要记得把此对象的引用设置为null;
4. 本对象删除不了的原因不一定是自己被引用了,也有可能是自己的孩子被外部引用了,孩子删不掉导致父亲也删不掉;
5. 除了引用需要删除外,系统组件或者全局工具、管理类如果提供了卸载方法的就一定要调用删除内部对象,否则有可能会造成内存泄露和性能损失;
6. 父对象立刻被删除了不代表子对象就会被删除或立刻被删除,可能会在后期被系统自动删除或第二次移除操作时被删除;
7. 如果父对象remove了子对象后没有清除对子对象的引用,子对象一样是不能被删除的,父对象也不能被删除;
8. 注册的事件如果没有被移除不影响自定义的强行回收机制,但有可能会影响正常的回收机制,所以最好是做到注册的事件监听器都要记得移除干净。
9. 父对象被删除了不代表其余子对象都删除了,找到一种状态的泄露代码不等于其他状态就没有泄露了,要各模块各状态逐个进行测试分析,直到测试任何状态下都能删除整个对象为止。
内存泄露举例:
1. 引用泄露:对子对象的引用,外部对本对象或子对象的引用都需要置null;
2. 系统类泄露:使用了系统类而忘记做删除操作了,如BindingUtils.bindSetter(),ChangeWatcher.watch()函数 时候完毕后需要调用ChangeWatcher.unwatch()函数来清除引用 ,否则使用此函数的对象将不会被删除;
类似的还有MUSIC,VIDEO,IMAGE,TIMER,EVENT,BINDING等。
3. 效果泄露:当对组件应用效果Effect的时候,当本对象本删除时需要把本对象和子对象上的Effect动画停止掉,然后把Effect的target对象置null; 如果不停止掉动画直接把 Effect置null将不能正常移除对象。
4. SWF泄露:要完全删除一个SWF要调用它的unload()方法并且把对象置null;
5. 图片泄露:当Image对象使用完毕后要把source置null;(为测试);
6. 声音、视频泄露: 当不需要一个音乐或视频是需要停止音乐,删除对象,引用置null;
内存泄露解决方法:
1. 在组件的REMOVED_FROM_STAGE事件回掉中做垃圾处理操作(移除所有对外引用(不管是VO还是组件的都需要删除),删除监听器,调用系统类的清除方法)
先remove再置null, 确保被remove或者removeAll后的对象在外部的引用全部释放干净;
2. 利用Flex的性能优化工具Profile来对项目进程进行监控,可知道历史创建过哪些对象,目前有哪些对象没有被删除,创建的数量,占用的内存比例和用量,创建过程等信息;
总结:关键还是要做好清除工作,自己设置的引用自己要记得删除,自己用过的系统类要记得做好回收处理工作。 以上问题解决的好的话不需要自定义强制回收器也有可能被系统正常的自动回收掉。
代码优化:
FLEX how to reduce the amount of code to reduce memory consumption
These are some ways to reduce the code or memory, select an author of the network.
1. Avoid the new operator when creating Arrays
var a = [];
NOT:
var a = new Array();
2. Arrays are expensive to create, do so conservatively
var vanityCollection01 : Array = new Array();
var vanityCollection02 : Array = new Array();
var vanityCollection03 : Array = new Array();
var vanityCollection04 : Array = new Array();
3. Fastest way to copy an array:
var copy : Array = sourceArray.concat();
4. Setting values in Arrays is slow
employees.push( employee );
employees[2] = employee;
5. Getting values from Arrays is twice as fast as setting
var employee : Employee = employees[2];
6. Use static for properties methods that do not require an object instance
StringUtils.trim( "text with space at end " );
Class definition:
package
{
public final class StringUtils
{
public static function trim( s : String ) : String
{
var trimmed : String;
// implementation...
return trimmed;
}
}
}
7. Use const for properties that will never change throughout the lifecycle of the application
public const APPLICATION_PUBLISHER : String = "Company, Inc.";
8. Use final when no subclasses need to be created of a class
public final class StringUtils
9. Length of method/variable names doesn’t matter in ActionScript 3.0 (true in other langs)
someCrazyLongMethodNameDoesntReallyImpactPerformanceTooMuch();
10. One line assignments DO NOT buy any performance (true in other langs)
var i=0; j=10; k=200;
11. No difference in memory usage between an if statement and a switch statement
if ( condition )
{
// handle condition
}
IDENTICAL MEMORY USAGE:
switch ( condition ) {
case "A":
// logic to handle case A
break;
case "B":
// logic to handle case B
break;
}
12. Rank your if statements in order of comparisons most likely to be true
if ( conditionThatHappensAlot ) {
// logic to handle frequently met condition
} else if ( conditionThatHappensSomtimes ) {
// handle the case that happens occaisonally } else {
// handle the case that doesn’t happen that often
}
13. AVM promotes int to Number during calculations inside loops (VM has been changing, from 9 to 10, so int, uint and number conversions aren’t as slow as they used to be.)
14. Resolve issues of promotion, unknown, or incorrect object types
15. Use uint sparingly, it can be slow (VM has been changing, from 9 to 10, so int, uint and number conversions aren’t as slow as they used to be.)
var footerHex : uint = 0x00ccff;
16. Use integers for iterations
(var i: int = 0; i < n; i++)
NOT
for (var i: Number = 0; i < n; i++)
17. Don’t use int with decimals
var decimal : Number = 14.654;
NOT:
var decimal : int = 14.654;
18. Multiply vs. Divide: instead of 5000/1000 use: 5000*0.001
19. Locally store function values in for and while statements instead of repeatedly accessing them
for (..){ a * 180 / Math.PI; }
declare: toRadians = a*180/Math.PI;
outside of the loop
20. Avoid calculations and method calls in loops
var len : int = myArray.lengh;
for (var i=0;i<len;i++){}
NOT:
for (var i=0;i< myArray.lengh;i++){ }
21. Use RegEx for validation, use string methods for searching
// postal code validation example using regular expressions
private var regEx:RegExp = /^[A-Z][0-9][A-Z] [0-9][A-Z][0-9]$/i;
private function validatePostal( event : Event ) : void
{
if( regEx.test( zipTextInput.text ) )
{
// handle invalid input case
}
// search a string using String methods
var string : String = "Search me";
var searchIndex : int = string.indexOf( "me" );
var search : String = string.substring(searchIndex,searchIndex+2);
22. Reuse objects to maintain a “memory plateau” DisplayObjects, URLLoader objects
23. Follow the Flex component model:
createChildren(); commitProperties(); updateDisplayList();
24. Only use Datagrids as a last resort (make sure you can’t implement in a regular List first)
25. Avoid Repeaters for scrollable data
26. Avoid the setStyle() method (One of the most expensive calls in the Flex framework)
27. Using too many containers dramatically reduces the performance of your application
<mx:Panel>
<mx:VBox>
<mx:HBox>
<mx:Label text="Label 1" />
<mx:VBox>
<mx:Label text="Label 2" />
</mx:VBox>
<mx:HBox>
<mx:Label text="Label 3" />
<mx:VBox>
<mx:Label text="Label 4" />
</mx:VBox>
</mx:HBox>
</mx:HBox>
</mx:VBox>
</mx:Panel>
28. You do not need to always use a container tag as the top-level tag of components Totally valid component, no top level container needed:
<mx:Image xmlns:mx="http://www.adobe.com/2006/mxml"
source="avatar.jpg" width="200" height="200" />
29. Remove unnecessary container wrappers to reduce container nesting
30. Avoid: The VBox container inside an tag, (eliminates redundancy)
<mx:Panel>
<mx:Label text="Label 1" />
<mx:Label text="Label 2" />
</mx:Panel>
<mx:Panel>
<mx:VBox>
<mx:Label text="Label 1" />
<mx:Label text="Label 2" />
</mx:VBox>
</mx:Panel>
31. Avoid: VBox container inside an mx:Application tag, (eliminates redundancy)
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx=http://www.adobe.com/2006/mxml>
<mx:Label text="Label 1" />
<mx:Label text="Label 2" />
</mx:Application>
NOT:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx=http://www.adobe.com/2006/mxml>
<mx:VBox>
<mx:Label text="Label 1" />
<mx:Label text="Label 2" />
</mx:VBox>
</mx:Application>
32. Set the recycleChildren property to true to improve a Repeater object’s performance (re-uses previously created children instead of creating new ones)
<mx:Script>
<![CDATA[
[Bindable]
public var repeaterData : Array = ["data 1", "data 2"];
]]>
</mx:Script>
<mx:Repeater id="repeater" dataProvider="{repeaterData}">
<mx:Label text="data item: {repeater.currentItem}"/>
</mx:Repeater>
33. Keep framerate set at 60 fps or lower
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx=http://www.adobe.com/2006/mxml
frameRate="45">
</mx:Application>
34. Avoid multiple display manipulations per frame
35. Code against ENTER_FRAME events instead of Timer events
public function onEnterFrame( event : Event ) : void
{ }
private function init() : void {
addEventListener( Event.ENTER_FRAME, onEnterFrame );
}
NOT:
public function onTimerTick( event : Event ) : void
{
}
private function init() : void {
var timer : Timer = new Timer();
timer.start();
timer.addEventListener( TimerEvent.TIMER, onTimerTick );
}
36. To defer object creation over multiple frames use:
<mx:Container creationPolicy="queued"/>
37. Alpha = 0 is not the same as visible = false (Objects marked invisible are passed over)
loginButton.visible = false;
NOT:
loginButton.alpha = 0;