A homework assignment I was recently given for a Java programming class involved a competition to see who could create the most optimized implementation of an interface which was provided by the instructor. It was a challenging and very fun assignment that I think the whole class enjoyed. I didn’t win the competition but still came out a winner because of my heightened interest in application optimization and performance tuning that I gained.
I’m personally a pretty big fan of coding standards and have been ribbed by many developers over some of the longer method, variable and class names that I sometimes choose. I've always leaned toward the side of programming that employs standards and frameworks . Rather than spending a ton of time digging around in compiler specs and messing with GC (Garbage Collection) for reasons of performance, tuning and optimization. I was leaving this to the seasoned programmers creating the standards and frameworks I use.
This isn’t to say I’ve never paid attention to performance and I enjoy building slow applications. It’s almost like two different worlds; the optimization world and the standards world. They don’t always agree with each other. There can sometimes be a trade off for performance over readability and organization or vice-versa. This article is meant to stand next to the Flex Best Practices articles that I authored.
While creating my concrete implementation for the homework assignment I discovered a powerful profiling engine in NetBeans. The NetBeans profiling engine helped me understand some of the memory usage and consumption of each property, method call and object instantiation in my program. This profiler in NetBeans is very similar to the one found in Flex Builder. Both are very powerful and very useful. I've been exploring the Flex Profiler in greater detail lately as well and using it to eradicate memory leaks for a real world application I’ve been refactoring to best practices lately.
The Java optimization homework has increased my interest in optimization and profiling for ActionScript 3.0 and Flex development. I've been piecing together ActionScript optimization techniques and practices from around the web for a couple years now. Some of these techniques are in opposition to what the standards dictate but most of software development is this way. You have to learn when to use some techniques and when to leave some out.
Here is a round up of ActionScript 3.0 and Flex optimization techniques and practices. I’ve scoured the web for and filtered practices and techniques that can be adopted into your application development process.
=======================================================
前面说的全是屁话下面才是例子说明!很重要:
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
常量 (用const 声明的量)的值在程序的整个生命周期中都不会变. (又是一句屁话)
public const APPLICATION_PUBLISHER : String = "Company, Inc.";
8. Use final when no subclasses need to be created of a class
当某个类不需要子类继承时,对该类使用final关键字,阻止被继承
public final class StringUtils
9. Length of method/variable names doesn't matter in ActionScript 3.0 (true in other langs)
方法名属性名的长短不会对程序有任何影响!原因是只有他们的值在才进入avm进行编译(这也是为什么我们进行反编译后,发现变量名怪怪的,经常是带"_" 这个符号!这是计算机自动分配的)
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语句和switch 在访问存储方面没有任何区别!
但是我觉得switch的效率好像高一些!
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语句里概率最大的(即最容易出现的情况)放在前面
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.)
AVM机建议在for循环尽量使用Number类型!
14. Resolve issues of promotion, unknown, or incorrect object types
尽量使用明确的变量类型 即其type要明确!这会提高程序的效率!(thinking in java 第四版里讲过这)
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.)
尽量少使用uint类型,因为它的速度很慢,最慢的!最好只在涉及到颜色值时才使用它。
var footerHex : uint = 0x00ccff;
16. Use integers for iterations
在for循环里使用int类型的变量
(var i: int = 0; i < n; i++) <推荐>
NOT for (var i: Number = 0; i < n; i++) <不推荐>
17. Don't use int with decimals
对带小数点的数使用Number类型
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循环外面使用而不要在 {}里使用
for (..){ a * 180 / Math.PI; }
declare: toRadians = a*180/Math.PI; outside of the loop
20. Avoid calculations and method calls in loops
尽量在for循环里少做些运算
比如数组的长度length应该在外面计算!
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
使用RegEXp对象进行结果验证,而应该使用String类型的方法进行搜索 替换等
// 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)
少使用DataGrid 很占内存
25. Avoid Repeaters for scrollable data
26. Avoid the setStyle() method (One of the most expensive calls in the Flex framework)
少使用setStyle方法它很耗内存
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,31例子是举例说明
30. Avoid: The VBox container inside an tag, (eliminates redundancy)
<推荐>
<mx:Panel>
<mx:Label text="Label 1" />
<mx:Label text="Label 2" />
</mx:Panel>
<不推荐,应将多余的VBox容器去掉>
<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
<将帧频设置为60或者低于60>
<?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
多使用ENTER_FRAME, 少用Timer 因为Timer很耗内存
用getTime()可以解决计时不准确的问题 另外Timer 也不是很精确
<推荐:>
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)
alpha值为0并不表示其不可见 一样的占内存!应使用 visible =false
loginButton.visible = false;
NOT: loginButton.alpha = 0; (原文http://www.insideria.com/2009/04/51-actionscript-30-and-flex-op.html)
为了使上面的更好理解 下面是我对Java的部分理解对上面有帮助:
Java基础:
List 类是容器 用来存放序列 。 Maps 是容器,它是关联数组 。 Sets 类 也是容器,保存每种类型对象的一种 。
List的两种数组:
ArrayList :访问数组里阿妈的任何一个数组的时间都是一样的 。然而LinkedList:越深的所以访问所需的时间越长。
插入一个元素到数组里。使用ArrayList的时间较长,LinkedArray的时间较短 。
具体化的数组有利于回收: ArrayList<Shape> shapes = new ArrayList<Shape>();
相应的as里 var shapes :Vector.<Shape> =new Vector.<Shape>();
局部变量都是保存在stack里!
动态创建的对象都保存在堆里(heap也就是a pool of memory <记忆池>),动态对象一般都是运行时创建的
堆heap分配给动态变量所需的时间比在栈stack里分配内存要的时间长.堆heap内存分配依赖于它的存储机制。动态分配机制更复杂和多变化 。
Java只用动态(dynamic)分配存储 :即:我们创建新的对象(动态对象)需要new 构造器。他们都存储在堆heap里 。 AS类似 。
在栈里创建的对象(局部变量),编译器能决定它存在多长的时间,然后自动的销毁它 。
然而堆里heap里的对象,编译器不知道它的生命周期(即不知道什么时候它该销毁),在C++里,我们要人为的编程去销毁它(堆heap里的对象)。在java里
存在GC(垃圾回收器)能很好的防止内存泄露 。
Register(寄存器):它的存储速度是最快的,速度第一 。因为它和其他的存储方式不同,它位于处理器内部。但是寄存器的数量有限!只有当其需要时才分配,我们 不能直接
操作控制寄存器 .但是C++可以将寄存器分配给编译器 。
栈stack :它位于一般的随机访问存储器里(RAM)。栈里能够快速高效的分配内存,它的速度只比Register(寄存器)慢,速度第二 。stack里的变量都具有确定的生命周期!
这限制了它的多样可变性。局部变量全部存储在stack里,生命周期到了自动销毁!此外,对象Object的引用也保存在栈stack里 ,而对象Object本身则保存在堆heap里。
堆heap : 它也位于访问存储器里(RAM).所有的JAVA Object对象都位于堆heap里。与栈stack不同的是,heap的优点在于编译器不需要知道存储的的对象在堆heap上保存多长的时间
!因此这增加了堆heap存储的多样性。当你需要一个对象时,只需new 一下。堆heap就自动给该对象分配内存 。注意:在堆heap上分配内存消耗的时间比在栈stack里消耗的多 。
Constant 存储:常量存储 .位于只读存储器(ROM)。常量不可更改!
Non-RAM存储: 程序外部数据,当程序未运行时就存在。其主要有两种:
@1 : 流对象 :对象被转化为字节流,然后传输到其他的机器上。
@2 : 持续存储对象: 这些对象被写入磁盘。当程序终止时依然存在 。
上面两种存储方式都是将对象转化为其他媒介。这些对象能够被还原RAM(随即访问存储器)里的对象。
对于一些基本类型:我们不需要用引用和new 而是直接持有该值。
下面是一些基本类型:
boolean char byte short int long float double void
这些类型是直接持有值而不是引用 。并且这些值存储在stack里
Number: 31-36ms
uint: 105-225ms
Number: 24-36ms
uint: 25-37ms
Number: 26-43ms
uint: 57-92ms
Number: 34-64ms
uint: 184-278ms
Number: 39-64ms
uint: 207-280ms
Number: 44-55ms
uint: 85-113ms
Number: 61-114ms
uint: 71-130ms