NSTaggedPointer
2020-07-19 本文已影响0人
三国韩信
TaggedPointer是苹果引入的对内存管理进一步优化的一种策略。下面以NSString为例,说明它。showCode:
一、用@"" 这种初始化的字符串
NSString *string = @"123456";
NSLog(@"%@,%p,%@",string,self.string,[string class]);
打印结果:123456, 0x1076e9198, __NSCFConstantString
可以看出,这种情况下的string是一个__NSCFConstantString类型,看它的内存地址,比不是放在栈区,也不是堆区,是放在常量区的。可见__NSCFConstantString代表的是一个字符串常量。
注: 这种写法也是一样的,[[NSString alloc] initWithString:@"222"];
二、用stringWithFormat初始化的字符串
NSString * s1 = [NSString stringWithFormat:@"123456789"];
NSLog(@"%@,%p,%@",s1,s1,[s1 class]);
NSString * s2 = [NSString stringWithFormat:@"1234567890"];
NSLog(@"%@,%p,%@",s2,s2,[s2 class]);
NSString * s3 = [[NSString alloc] initWithFormat:@"123456789"];
NSLog(@"%@,%p,%@",s3,s3,[s3 class]);
NSString * s4 = [[NSString alloc] initWithFormat:@"1234567890"];
NSLog(@"%@,%p,%@",s4,s4,[s4 class]);
打印结果:
123456789, 0xdb939874c869cf6b, NSTaggedPointerString
1234567890, 0x600003bbb600, __NSCFString
123456789, 0xdb939874c869cf6b, NSTaggedPointerString
1234567890, 0x600003bd1000, __NSCFString
这里,就出现了NSTaggedPointerString。那么何为NSTaggedPointerString呢?
是苹果对于一些小变量(小的数据,短的字符串)的一种表示的方式。(NSString、NSNumber)
NSTaggedPointer类型的数据,它的表现形式为:地址+值。它的数据本身就存储在地址里,它不用另外的去开辟堆栈空间之类的,所以他也不适用于苹果对普通对象的那套retain/release模式。
TaggedPointer
那么多小的变量算是苹果所谓的小数据呢,网上传说的是字符串只要少于9个就是,所以上面的例子中分别用了9个和10个字符来实验。而且,多次初始化相同的NSTaggedPointerString,它的地址是不变的。
正因为NSTaggedPointerString不存在retain和release的操作,所以面试中也经常被坑。如下题:
- (void)taggedPointerDemo {
self.queue = dispatch_queue_create("com.taggedPointer.cn", DISPATCH_QUEUE_CONCURRENT);
for (int i = 0; i<10000; i++) {
dispatch_async(self.queue, ^{
self.nameStr = [NSString stringWithFormat:@"cooci"];
NSLog(@"%@",self.nameStr);
});
}
}
-(void)nomalStringDemo {
self.queue = dispatch_queue_create("com.nomalString.cn", DISPATCH_QUEUE_CONCURRENT);
NSLog(@"来了");
for (int i = 0; i<10000; i++) {
dispatch_async(self.queue, ^{
self.nameStr = [NSString stringWithFormat:@"和谐学习,不急不躁,才能进步"];
NSLog(@"%@",self.nameStr);
});
}
}
以上2个方法运行,哪个会奔溃?
解析:上面都是多线程异步去调用的,nomalStringDemo这个方法会奔溃。原因是这个方法里多线程去对self.nameStr赋值,
相当于调用了它的setter方法,它的setter方法里面有retain/release的操作,而这里又没有加锁,
多线程去调用release的话,会出现对同一个对象多次release的情况,所以会奔溃。
而第一方法不会奔溃,正是因为它的string是NSTaggedPointerString,它本身并不会去retain/release(或者说它的retain/release啥都没做),
而且他的地址都是一样的,所以不会奔溃。