6

この研究により、CoreFoundation CGColor オブジェクトの内部が理解できることを願っています。IOS宣言と一致するように見える無料のクォーツプロジェクトからCGColor構造体のサンプル定義を見つけることができました(私の研究に依存しています)。

typedef struct CGColor {
        CFRuntimeBase obj;

        CFTypeID colorID;
        CGColorSpaceRef colorSpace;
        CGPatternRef pattern;
        size_t numberOfComponents;
        CGFloat *components;
} *CGColorRef;

(colorID フィールドは、フリークォーツでは nextID と名付けられていますが、IOS による色の一意の識別子として意図されていると思いますので、次の識別子のようなものではありません。)

グローバルにスレッド セーフな一意の値が保持され、CGColor オブジェクトが作成されて colorID メンバーに割り当てられるたびに 1 ずつ増加します。ドキュメントに記載されていない CGColorGetIdentifier() 関数のみがこの値を返します。(単調に増加する id 値について推測しています。デバイスとキャリブレーションされたカラー ルックアップの間、またはその逆の変換中にパフォーマンスが向上する可能性があります。)

CoreGraphics とそのリソース ライブラリを確認しました。ripc_GetColor (libRIP.A.dylib) 関数だけが CGColorGetIdentifier() 関数を呼び出すことがわかりました。

CGColorGetIdentifier; のコール スタック (colorID に関する推測に役立つことを期待して)

0   com.apple.CoreGraphics CGColorGetIdentifier + 0
1   libRIP.A.dylib          ripc_GetColor + 112
2   libRIP.A.dylib          ripc_DrawGlyphs + 1740
3   com.apple.CoreGraphics  CGContextDelegateDrawGlyphs + 108
4   com.apple.CoreGraphics  drawGlyphs + 284
5   com.apple.CoreGraphics  CGContextShowGlyphsWithAdvances + 208

現在のカラー グラフィックス コンテキスト操作では、ripc_GetColor() は現在のストローク/塗りつぶしの色の変換を計算し、この色の参照と colorID を使用してこれらの変換をキャッシュします。

したがって、次のグラフィックス コンテキスト操作では、ripc_GetColor() は、以前にキャッシュされた参照と現在の参照および colorID の値を比較して、最後のグラフィックス コンテキスト操作で既にキャッシュされた色変換をスキップします。

解放されたオブジェクトの参照 (メモリ アドレス) は、別のオブジェクトの作成中に使用できることがわかっています。したがって、参照を確認するだけでは、同じ色のオブジェクトが有効であることを確認するのに十分ではなく、内容または何らかのハッシュ値を比較する必要があります。したがって、この目的のために一意の識別子の値を使用できます。

ただし、識別子は単一のオブジェクトとその参照に使用されている可能性があるため、ID のみを比較するだけで十分です。ただし、ref と id の両方が使用されます。このような単純で重要なことを見落としていたとは思えません。

したがって、id と ref の両方を比較する必要性を見つけようとしますが、id だけを比較するだけで十分です。

以前のアプローチから残っているので、完全に放棄することはできませんでしたか?

4

1 に答える 1

1

私の理解が正しければ、なぜ誰かがキャッシュを

void DoSomethingWith(CGColorRef c)
{
    static CGColorRef cached_c = NULL;
    static CFTypeID cached_colorID;

    if (c == cached_c && c->colorID == cached_colorID) ...

単にではなく

void DoSomethingWith(CGColorRef c)
{
    static CFTypeID cached_colorID = 0;

    if (c->colorID == cached_colorID) ...

? さて、明らかな理由は2つあります

  • ランダム アクセス メモリはランダム アクセスではありません。逆参照cはおそらく遅い操作です (キャッシュ ミスは多くのナノ秒を無駄にします)。そのため、安価なポインター比較を先頭に追加することで 90% の時間でこれらのナノ秒を節約できる場合は、そうしましょう。

  • どのように初期化しますcached_colorIDか? 上記の最初の実装で、ユーザーが API コントラクトを尊重し、常に null 以外を渡すと仮定すると、==がcわかれば、それもわかり、意味のある値が に含まれます。2 番目の実装では、最初に渡されたユーザーが.ccached_ccached_c != NULLcached_colorIDcc->colorID == 0

これらのいずれかが、あなたが見ていることを Apple が行った理由かどうかはわかりませんが、確かな可能性があるように思えますね。

于 2013-11-03T00:12:33.243 に答える