15

「概要」セクションのARCリリースノートへの移行を読みました。彼らは言った :

ARCは、コンパイル時にコードを追加することで機能し、オブジェクトが必要なだけ存続するようにしますが、それ以上は存続しません。概念的には、適切なメモリ管理呼び出しを追加することにより、手動参照カウント(高度なメモリ管理プログラミングガイドで説明)と同じメモリ管理規則に従います。

コンパイラが正しいコードを生成するために

ARCがコードを修正した結果はどうなるのだろうか。

私の質問:変化を見ることができますか?(割り当て、保持、割り当て、または解放の用語で。アセンブリレベルではありません!)

理由: ARCモードを使用しない古い伝統的な開発でベストプラクティスのコードを見るのは良いことだと思うからです。

4

3 に答える 3

27

clangのARCは、コードをObjCからObjCに書き換えても機能しませんが、コード生成中に追加の保持/解放LLVMビットコードを発行します。つまり、LLVM IR /アセンブリレベルに移動せずに、コンパイラがどのようにそれを「修正」するかを知ることはできません。


あなたが言ったように、ARCがLLVMビットコードを発行する場合。コンパイルプロセスにかかる時間を短縮する目的で作成されていますか?(複雑でないObjCコード、ヘッダーファイルが少ない?)

コンパイラーがコードを通過する回数を減らすことができれば、常に優れています。


アセンブリレベルでコードを表示する例やユーティリティを教えてください。

アセンブリコードを取得するには、次のいずれかを実行できます。

  1. コンパイラから直接アセンブリを生成します。コマンドラインで-S、コンパイラを呼び出すときにフラグを追加します。結果は.S、アセンブリコードを含むファイルです。Xcodeプロジェクトで、ソースコードファイルを開き、[製品](メニューバー)→ [出力の生成] → [アセンブリファイル]に移動します。

  2. オブジェクトファイルを生成し、それを逆アセンブルします。組み込みコマンドotool -tvV <file>は逆アセンブルを実行でき、otx(無料)やIDA(評価用に無料)などの高度なツールがあります。

ルート2の方がゴミの発生が少なく、逆アセンブルツールを構成してより有用な情報を生成できるためです。とにかく、どちらの方法でも、アセンブリコードを読み取れる必要があります。

このコードを例として取り上げます。

- (BOOL)application:(UIApplication*)application 
        didFinishLaunchingWithOptions:(NSDictionary*)launchOptions
{
   self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
   self.window.backgroundColor = [UIColor whiteColor];
   [self.window makeKeyAndVisible];
   return YES;
}

コンパイル後、次のアセンブリが作成されます(IDAを使用して分析)。

-[SomeAppDelegateアプリケーション:didFinishLaunchingWithOptions:]:
    プッシュ{r4-r7、lr}
    r7、sp、#0xCを追加
    str.w r8、[sp、-#0x4]!
    サブsp、sp、#0x18
    movw r1、#(0x343c-0x2574); @selector(alloc)
    mov r8、r0
    movt.w r1、#0
    mov r0、(0x3464-0x2576); _OBJC_CLASS _ $ _ UIWindow
    r1、pcを追加
    r0、pcを追加
    ldr r1、[r1]
    ldr r0、[r0]
    blx _objc_msgSend
    mov r1、(0x3440-0x258e); @selector(mainScreen)
    mov r6、r0
    movw r0、#(0x3468-0x2594); _OBJC_CLASS _ $ _ UIScreen
    r1、pcを追加
    movt.w r0、#0
    r0、pcを追加
    ldr r1、[r1]
    ldr r0、[r0]
    blx _objc_msgSend
    mov r7、r7
    blx _objc_retainAutoreleasedReturnValue
    mov r5、r0
    cbz r5、L25ba
    movw r0、#(0x3444-0x25b2); @selector(bounds)
    mov r1、r5
    movt.w r0、#0
    r0、pcを追加
    ldr r2、[r0]
    r0、sp、#0x8を追加します
    blx _objc_msgSend_stret
    b L25c4

L25ba:
    r0、sp、#0x8を追加します
    vmov.i32 q8、#0x80
    vstmia r0、{d16-d17}

L25c4:
    mov r1、(0x3448-0x25d2); @selector(initWithFrame :)
    ldr r0、[sp、#0x10]
    r1、pcを追加
    ldr r2、[sp、#0x8]
    ldr r3、[sp、#0xc]
    ldr r4、[sp、#0x14]
    stmea.w sp、{r0、r4}
    mov r0、r6
    ldr r1、[r1]
    blx _objc_msgSend
    mov r4、r0
    mov r0、(0x344c-0x25F2); @selector(setWindow :)
    mov r2、r4
    r0、pcを追加
    ldr r1、[r0]
    mov r0、r8
    blx _objc_msgSend
    mov r0、r4
    blx _objc_release
    mov r0、r5
    blx _objc_release
    mov r0、(0x3450-0x2610); @selector(window)
    r0、pcを追加
    ldr r5、[r0]
    mov r0、r8
    mov r1、r5
    blx _objc_msgSend
    mov r7、r7
    blx _objc_retainAutoreleasedReturnValue
    mov r1、(0x3454-0x2630); @selector(whiteColor)
    mov r6、r0
    movw r0、#(0x346C-0x2636); _OBJC_CLASS _ $ _ UIColor
    r1、pcを追加
    movt.w r0、#0
    r0、pcを追加
    ldr r1、[r1]
    ldr r0、[r0]
    blx _objc_msgSend
    mov r7、r7
    blx _objc_retainAutoreleasedReturnValue
    mov r4、r0
    mov r0、(0x3458-0x2652); @selector(setBackgroundColor :)
    mov r2、r4
    r0、pcを追加
    ldr r1、[r0]
    mov r0、r6
    blx _objc_msgSend
    mov r0、r4
    blx _objc_release
    mov r0、r6
    blx _objc_release
    mov r0、r8
    mov r1、r5
    blx _objc_msgSend
    mov r7、r7
    blx _objc_retainAutoreleasedReturnValue
    mov r4、r0
    mov r0、(0x345C-0x2680); @selector(makeKeyAndVisible)
    r0、pcを追加
    ldr r1、[r0]
    mov r0、r4
    blx _objc_msgSend
    mov r0、r4
    blx _objc_release
    movs r0、#1
    sp、sp、#0x18を追加
    ldr.w r8、[sp]、#4
    pop {r4-r7、pc}

詳細に立ち入ることなく、多くの_objc_releaseとが存在することがわかります_objc_retainAutoreleasedReturnValueこれらは、コード生成中にARCが挿入するものです。手作業で逆コンパイルすると、次のようになります。

UIScreen* r5 = objc_retainAutoreleasedReturnValue([UIScreen mainScreen]);
CGRect sp8 = r5 != nil ? [r5 bounds] : CGRectZero;
UIWindow* r4 = [[UIWindow alloc] initWithFrame:sp8];
[self setWindow:r4];
objc_release(r4);
objc_release(r5);

UIWindow* r6a = objc_retainAutoreleasedReturnValue([self window])
UIColor* r4a = objc_retainAutoreleasedReturnValue([UIColor whiteColor])
[r6a setBackgroundColor:r4a];
objc_release(r4a);
objc_release(r6a);

UIWindow* r4b = objc_retainAutoreleasedReturnValue([self window])
[r4b makeKeyAndVisible];
objc_release(r4b);

return 1;

これは、 @croaldのリンクで説明されているものとまったく同じです。

于 2012-05-03T15:15:38.600 に答える
3

Mike Ashは、ここでARC実装について非常に明るい議論をしています:http://www.mikeash.com/pyblog/friday-qa-2011-09-30-automatic-reference-counting.html

彼は、C関数呼び出し(objc_retain()、objc_release()、objc_retainAutoreleaseReturnValue()、およびそれが役立つ場合は他のいくつか)を挿入するレベルでそれについて説明します。そのように書かれているので、コンパイラーは末尾呼び出しの最適化を使用して不要な手順を排除します。

したがって、簡単に言うと、ARCは古いバージョンのObjeciveCで使用していたのと同じ[retain]/ [release]メソッドを使用しないため、ARCで前処理されたコードを確認しても、必ずしもその方法を説明できるとは限りません。自分でやる。

ARCは、コンパイラの前処理ステップとして実装されることは珍しくありません。ObjectiveCの多くの機能がこの方法で実装されていると思います。

于 2012-05-12T14:09:30.093 に答える
0

いいえ、LLVMのアセンブリレベルの詳細に立ち入ることなく、そのような詳細に立ち入ることはできません。

于 2012-05-12T16:53:57.733 に答える