I was working on some blitting code today and after profiling it found that I was creating 1000s of new rectangles. I was shocked because I only had 1 or 2 different new Rectangle() calls or I was using the .rect property of BitmapData.
I started commenting out huge swathes of code until I was left with this code in my sprite class:
canvas.bitmapData.copyPixels(_bitmapData, _bitmapData.rect, destination, null, null, true);
I cached the result of _bitmapData.rect at object creation and my thousand of new rectangle calls were suddenly gone from the profil开发者_C百科er.
Why the heck would BitmapData.rect create a new rectangle? Is there a way to check the core libraries or something and confirm this is true? It seems baffling.
Bethanny Anne said:
Why the heck would BitmapData.rect create a new rectangle? Is there a way to check the core libraries or something and confirm this is true? It seems baffling.
Imagine the following hypothetical situation where BitmapData.rect
always returns the same Rectangle instance:
public function BitmapDataRectTest()
{
var bmp:BitmapData = new BitmapData(100, 100, true, 0);
var rect1:Rectangle = bmp.rect;
rect1.width = 200;
var rect2:Rectangle = bmp.rect;
trace(rect2.width); // 200 <--- this would be wrong,
// the BitmapData is still only 100 pixels wide.
}
BitmapData.rect
returns a new instance every time to avoid that situation and to make sure you are getting the correct data in the returned Rectangle
instance.
Final note: this relates to 'pass-by-value' (primitive types) and 'pass-by-reference' (complex type) variables. For more info check out google or other posts on stackoverflow: Pass by reference or pass by value?
Interesting observation.
You can use the ===
operator to check if two instances of any Object
are the same.
It's likely that BitmapData
internally uses different data structures to maintain its visual state. The rect
property must be implemented as a getter function. However, one would expect that because the dimensions of BitmapData
are immutable, that the Rectangle
object would never need to be recreated, or even re-computed at all.
Edit: The rect
property on BitmapData
is read-only (no setter), however the properties on a Rectangle
are not. Creating a new instance of Rectangle
ensures that external objects cannot make mutations.
Yes, it sounds discouraging, but if you will take a look at BitmapData class source code you will discover this:
public class BitmapData extends Object implements IBitmapDrawable {
...
public function get rect() : Rectangle {
return new Rectangle(0, 0, this.width, this.height);
}
...
}
So the answer is Yes, AVM creates new instance of Rectangle in the heap every time you retrieve it through accessor-function.
Yes, BitmapData.rect is apparently a getter that creates new rectangle on access.
You can prove it by comparing references or by examining memory addresses:
Example:
package
{
import flash.display.Sprite;
import flash.display.BitmapData;
import flash.geom.Rectangle;
public class BitmapDataRectTest extends Sprite
{
public function BitmapDataRectTest()
{
var bmp:BitmapData = new BitmapData(100, 100, true, 0);
trace(bmp.rect == bmp.rect); // false
var rect1:Rectangle = bmp.rect;
var rect2:Rectangle = bmp.rect;
trace("Place breakpoint here and look at rect1 and rect2 memory addresses");
// rect1 address on my pc: @6900f71
// rect2 address on my pc: @6900f41
}
}
}
EDIT Similar behaviour in native classes:
DisplayObject.transform
: returns new Transform instance on each accessTransform.colorTransform
: returns new ColorTransform instance on each accessDisplayObject.filters
: returns new Array instance on each access- ...you can find a lot of other cases when you get a copy of an internal object.
In all of these cases classes protect themselves from being broken. Just think of it this way: when a class uses aggregation it can not expose it's aggregated instances as is, because otherwise it would be necessary to notify main class of changes in internal objects when they occur. That's a lot of logic to update and validate changes in each field of each aggregated instance.
精彩评论