Static vs. Non-Static
Tip #8 in my Top 10 Performance Tips For 2012 was to reduce static accesses of variables, functions, etc. in favor of non-static variables and, especially, local variables. I neglected to reference one of my articles and it was pointed out to me that I hadn’t actually written such an article! So today I’ll elaborate on my tip and show why you should prefer non-static and local variables so you can find out just why it deserves its place as a top tip.
To test my claim that static is significantly slower than non-static and local variables, let’s look at a simple test app:
package { import flash.display.*; import flash.text.*; import flash.utils.*; public class StaticTest extends Sprite { private var tf:TextField = new TextField(); private var nonStatic:Number = 0; private function row(...c): void { tf.appendText(c.join(",")+"\n"); } public function StaticTest() { tf.autoSize = TextFieldAutoSize.LEFT; addChild(tf); var REPS:int = 100000000; var i:int; var temp:Number; var local:Number = 0; var beforeTime:int; row("Variable", "Time"); beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { temp = Math.PI; } row("Static", (getTimer() - beforeTime)); beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { temp = this.nonStatic; } row("Non-Static", (getTimer() - beforeTime)); beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { temp = local; } row("Local", (getTimer() - beforeTime)); } } }
I ran this test with the following environment:
- Flex SDK (MXMLC) 4.5.1.21328, compiling in release mode (no debugging or verbose stack traces)
- Release version of Flash Player 11.1.102.55
- 2.4 Ghz Intel Core i5
- Mac OS X 10.7.2
And got these results:
Variable | Time |
---|---|
Static | 760 |
Non-Static | 214 |
Local | 198 |
As you can see, the non-static and local variables far outperform the static variables. If you’re going to be doing a lot of variable access, you should definitely consider caching that variable as a non-static field or local variable.
Spot a bug? Have a tip? Post a comment!
#1 by BlooDHounD on January 11th, 2012 ·
add plz
private static var staticVar:Number = 0;
and repeat test
#2 by NemoStein on January 11th, 2012 ·
I want to see this, too.
Static members that is part of the instance class could perform different, maybe.
#3 by ben w on January 11th, 2012 ·
interesting stuff
don’t forget though that static access from the class which defines is a valid competitor…
Variable,Time
Static,1112
Own Static (StaticTest.PI),1118
Own Static (PI),245
Non-Static,252
Local,250
I added
private static const PI:Number = Math.PI;
to the top of your class and when accessed as PI rather than StaticTest.PI… it was actually the quickest a few times
(testing in release player v 11.1.102.55)
be interesting to see what results you get for that.
So if you had your own mathematics class, no harm to have statics such as PI, DEG_2_RAD, RAD_2_DEG as long as you access them as such (without the .)
#4 by jackson on January 11th, 2012 ·
Thanks for elaborating on the test. This really shows that the static lookup is the slow part, not the actual static. I suppose a better way to put it would be “use fewer static lookups”.
Thanks again for the testing and the results!
#5 by ben w on January 11th, 2012 ·
@BlooDHounD, doh beat me to it..serves me right for testing and typing at the same time
#6 by Aleksandr Makov on January 11th, 2012 ·
Thanks Jackson. And thanks ben_w, it is a bit more complete with your figures!
#7 by hexagonstar on January 11th, 2012 ·
Very interesting that PI is faster than StaticTest.PI, ben. I would had thought the opposite is true.
#8 by hexagonstar on January 11th, 2012 ·
I get these with ben’s class (tested as AIR release build):
Variable,Time
Static,596
Own Static (StaticTest.PI),218
Own Static (PI),171
Local,170
In all test runs Own Static (PI) was the fastest among the static accessed.
#9 by Chris on January 11th, 2012 ·
Could you benchmark the speed of setting context3D’s vertex buffer/constants/texture, and drawTriangles?
I’m into making a 3D engine, and I have it all working ( so far ), but I want to optimize it, and I’m not sure how I would do that.
I want to know which is faster, so I know which order so draw the objects.
That way I can sort them, and reduce the amount of times I have to set textures, or vertex buffers.
Is it faster to sort the 3D objects by texture, and then sort by geometry, or the other way around?
This would help a lot.
I hope you see this.
#10 by jackson on January 11th, 2012 ·
In general, changing the 3D state (e.g. textures) is a big performance hit because it interrupts the GPU’s pipelining. Ideally, you want to do multiple
drawTriangles
calls without changing anything. So you’re on the right track: group your draws such that you don’t have to change state between them. For example, if you have 10 enemy models to draw, draw all of them at once since they share the same texture, vertex buffers, and index buffers rather than drawing five of them, drawing the player, drawing the remaining five enemies, and then drawing the terrain.I will add this to my list of articles to write and go more in depth on it then. Thanks for the idea.
#11 by Chris on January 11th, 2012 ·
Thanks.
Can’t wait to see a more in depth explanation!
#12 by icekiller on January 14th, 2012 ·
Hello,
Test in my computer with the flash player 11,this result is
Variable,Time
Static,1018
Non-Static,380
Local,413
the local is slow than the non-static.Why?
#13 by Andreas Renberg on January 17th, 2012 ·
I extended this test a bit and came to two conclusions:
1. There is virtually no performance difference between “var” and “const” (which Jackson may have covered already, but I just wanted to double check, hoping Flash had some way of optimizing “compile time constants”)
2. It’s only looking up a static variable that has this huge performance hit (which just confirms the results of this blog post), not looking up an “external” variable (located within a different class)
If you make the “static class” a singleton and keep a reference to the instance locally, calling “this.mathInstance.PI” is still many times more efficient than calling the static constant (in fact, the speed difference between accessing the instance constant and a local constant is negligible)
The test is available here in case anyone else wants to test it:
https://gist.github.com/1627214
#14 by jackson on January 17th, 2012 ·
Glad to hear you’re coming to the same conclusions that I did. Also, very nice tip about the singleton: it’s definitely a way to reduce static accesses.
#15 by skyboy on January 29th, 2012 ·
While reviewing my compiled code to see what MXMLC is doing to it (to avoid performance pitfalls), I noticed that
ClassName.staticVar
results in agetlex
for the class, thengetproperty
for the ..property.staticVar
results in a single getlex for the class, and the property.The real killer here would appear to not be static access, but dynamic access. The simplest way to test the assumption would be to compare
ClassName.staticVar
vs.ClassName["staticVar"]
. If this is the case, then Adobe can improve performance of SWFs rather dramatically by making the compiler generate a single getlex for static properties, regardless ofstaticVar
orClassName.staticVar
.Interestingly, properties of superclasses also generate a
getlex
instruction unless you typethis.
in front of them.#16 by skyboy on January 29th, 2012 ·
Another note about properties.
this.prop = ...
results ingetlocal0, ..., setproperty
whileprop = ...
results in..., initproperty
. initproperty has much less code on Flash Player’s side, and could potentially result in faster code.#17 by jackson on January 29th, 2012 ·
It’s just these kinds of compiler issues that I’d love to cover. Thanks for the tips!
#18 by IngweLand on March 28th, 2013 ·
No longer valid. Got following results (ASC 2, FP 11.6, release version)
Variable,Time
Static,203
Non-Static,167
Local,167
#19 by jackson on March 28th, 2013 ·
I would say “less valid”. Static is still slower than non-static or local. It’s just not as slow as it used to be.