objc里的偽指針TaggedPointer


如果你看過我前面兩篇objc函數樞紐msgSend你印象中的NSString是這樣嗎,相信已經多次看過它的身影了,到底它是何物何作用,我今日就來揭開謎團。
我之所為稱呼它為偽指針,是因為它像幽靈一樣,沒有肉身(實例)但卻在能像objc對象實例那樣表現出各種行為。你能猜出下面代碼運行的結果嗎?

// non-arc
id unknown = (id)0x12345678;
NSLog(@"%@", unknown);
unknown = (id)0xa000000000032312;
NSLog(@"%@", unknown);
NSString* s12 = [NSString stringWithUTF8String:"12"];
NSLog(@"%@", s12);
[s12 isEqualToString:unknown];
NSLog(@"%d", *(int64_t*)&s12 == *(int64_t*)&unknown);

如果我隨便編寫一個地址0x12345678,然后用這個地址進行objc調用,[(id)0x12345678 retain]。相信大家第一反應是我正在對一個不明白的地址訪問,指向這個地址的指針大家叫它野指針,我正在向一個“野指針”操作。

如果我又隨便編寫一個地址像這們0xa000000000032312,並對這個地址進行objc調用[(id)0xa000000000032312 retain]。相信大家的反應是和上面舉例的情況一樣,盡管當中有人看過我們前面的文章知道這是一個TaggedPointer,但是我還是在對一個不可信的地址進行操作,當訪問0xa000000000032312內存地址的內容時將要出錯。

但結果卻是,0xa000000000032312地址的操作合法,並且用NSLog(@"%@", (id)0xa000000000032312)還打印出12。

大家都熟悉實例的構建過程,如[[NSString alloc] init]和[NSString string]。都必須為對像實例分配空間然后初始化。然而地址0xa000000000032312只是我隨便編造的,完全沒有在那個地址上分配過空間。
我再來調用[NSString stringWithUTF8String:"12"],返回了一個類型是NSTaggedPointerString實例的指針。指向的地址正是0xa000000000032312。直到這時0xa000000000032312的實例才被構建,然而對這個地址一訪問還是一個非法地址。

所以TaggedPointer只是一個偽指針,它的真相就在這個指針指向的地址的數值本身。
0xa000000000032312這個數值就像一個被壓縮的對像實例一樣,最高4位是isa的線索,參考前面介紹反匯編msgSend文章,最低8位是info信息,中間第9位起的48位是對像的content。用這副幽靈鏡來再看0xa000000000032312,什么都一清二楚了,{isa=0xa,coutent='\x31\x32',len=2}。這是NSString中一種名為EightBitsEncoding的情況。

為什么要有TaggedPointer,就讓我們來看一下性能。
用profile分別查看循環100M次的[@"ab" stringAppendByString:@"c"]和[NSString stringWithUTF8String:"abc"];
上一篇的例子可以找到[@"ab" stringAppendByString:@"c"]返回__NSCFString, [NSString stringWithUTF8String:"abc"]返回NSTaggedPointerString。
究竟它們之間有什么樣的性能差別呢?由於我的機器性能有限,profile時幾近運行不過來,所以沒有圖可截貼出,只能陳述一下情況。先是[@"ab" stringAppendByString:@"c"]返回__NSCFString的情況,CFString不斷地在緩慢分配,待到分配了1M個時,內存占用了50M,機器在profile運行中慘不忍睹,我果斷中止了。另一方面[NSString stringWithUTF8String:"abc"]返回NSTaggedPointerString的profile中,CFString數量沒有增長,內存自然也沒有消耗。好我將循環次數減少至1M次,不做profile,直接運行對比,NSTaggedPointerString的情況明顯要快出幾倍,因為根本沒有構建過實例(,用於返回的實例,中間里面的過程一樣還有其它臨時實例的)。

除了NSTaggedPointerString還有其它的TaggedPointer,你知道0xb0000000000000c2是什么嗎,趕緊試一試。

最后多謝大家再次觀看。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM