1

今日、いくつかのブリッティング コードに取り組んでいましたが、プロファイリングを行った後、何千もの新しい四角形を作成していることがわかりました。1 つまたは 2 つの異なる new Rectangle() 呼び出ししかなかったか、BitmapData の .rect プロパティを使用していたため、ショックを受けました。

スプライト クラスに次のコードが残るまで、大量のコードをコメント アウトし始めました。 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ます。

最後の注意: これは、'pass-by-value' (プリミティブ型) および 'pass-by-reference' (複合型) 変数に関連しています。詳細については、Google またはスタックオーバーフローの他の投稿をチェックしてください:参照渡しまたは値渡し?

于 2011-07-15T07:36:59.177 に答える
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: アクセスごとに新しい配列インスタンスを返します
  • ...内部オブジェクトのコピーを取得する場合、他の多くのケースを見つけることができます。

これらのすべてのケースで、クラスは自分自身を壊れないように保護します。このように考えてください。クラスが集約を使用する場合、集約されたインスタンスをそのまま公開することはできません。そうしないと、内部オブジェクトの変更が発生したときにメインクラスに通知する必要があるためです。これは、集約された各インスタンスの各フィールドの変更を更新および検証するための多くのロジックです。

于 2011-07-15T06:07:50.837 に答える
0

興味深い観察。

===演算子を使用して、any の 2 つのインスタンスObjectが同じかどうかを確認できます。

BitmapData内部でさまざまなデータ構造を使用して、視覚的な状態を維持している可能性があります。プロパティはゲッター関数として実装するrect必要があります。ただし、の次元BitmapDataは不変であるため、Rectangleオブジェクトを再作成する必要はなく、再計算する必要さえまったくないことが予想されます。

編集:rectプロパティBitmapDataは読み取り専用 (セッターなし) ですが、のプロパティはそうでRectangleはありません。の新しいインスタンスを作成するRectangleと、外部オブジェクトがミューテーションを作成できなくなります。

于 2011-07-15T06:33:07.637 に答える
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 に答える