1

我今天正在编写一些 blitting 代码,在对其进行分析后发现我正在创建 1000 个新矩形。我很震惊,因为我只有 1 或 2 个不同的新 Rectangle() 调用,或者我正在使用 BitmapData 的 .rect 属性。

我开始注释大量代码,直到在我的 sprite 类中留下这段代码: canvas.bitmapData.copyPixels(_bitmapData, _bitmapData.rect, destination, null, null, true);

我在创建对象时缓存了 _bitmapData.rect 的结果,我的数千个新矩形调用突然从探查器中消失了。

为什么 BitmapData.rect 会创建一个新的矩形?有没有办法检查核心库或其他东西并确认这是真的?似乎莫名其妙。

4

4 回答 4

1

贝瑟妮安妮 说:

为什么 BitmapData.rect 会创建一个新的矩形?有没有办法检查核心库或其他东西并确认这是真的?似乎莫名其妙。

想象以下假设情况,其中BitmapData.rect总是返回相同的 Rectangle 实例:

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每次都返回一个新实例以避免这种情况,并确保您在返回的Rectangle实例中获得正确的数据。

最后说明:这与“按值传递”(原始类型)和“按引用传递”(复杂类型)变量有关。有关更多信息,请查看 google 或 stackoverflow 上的其他帖子:按引用传递还是按值传递?

于 2011-07-15T07:36:59.177 回答
0

是的,这听起来令人沮丧,但如果你看一下 BitmapData 类的源代码,你会发现:

public class BitmapData extends Object implements IBitmapDrawable {
...
    public function get rect() : Rectangle {
        return new Rectangle(0, 0, this.width, this.height);
    }
...
}

所以答案是肯定的,AVM 每次通过访问函数检索它时都会在堆中创建新的 Rectangle 实例。

于 2011-07-15T18:51:04.090 回答
0

是的,BitmapData.rect 显然是一个在访问时创建新矩形的吸气剂。

您可以通过比较引用或检查内存地址来证明这一点:

例子:

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
        }
    }
}

编辑本机类中的类似行为:

  • DisplayObject.transform:在每次访问时返回新的 Transform 实例
  • Transform.colorTransform:在每次访问时返回新的 ColorTransform 实例
  • DisplayObject.filters:在每次访问时返回新的 Array 实例
  • ...当您获得内部对象的副本时,您会发现很多其他情况。

在所有这些情况下,类都会保护自己不被破坏。可以这样想:当一个类使用聚合时,它不能按原样公开它的聚合实例,因为否则有必要在内部对象发生更改时通知主类。更新和验证每个聚合实例的每个字段中的更改有很多逻辑。

于 2011-07-15T06:07:50.837 回答
0

有趣的观察。

您可以使用===运算符来检查 any 的两个实例Object是否相同。

内部很可能BitmapData使用不同的数据结构来维护其视觉状态。该rect属性必须实现为 getter 函数。然而,人们会期望,因为 的维度BitmapData是不可变的,所以Rectangle对象永远不需要重新创建,甚至根本不需要重新计算。

编辑: on的rect属性BitmapData是只读的(没有设置器),但是 a 的属性Rectangle不是。创建一个新的实例Rectangle确保外部对象不能进行突变。

于 2011-07-15T06:33:07.637 回答