评论

收藏

[iOS开发] 内存管理(二)之别小看了Tagged-Pointer关键时刻起到大作用

移动开发 移动开发 发布于:2022-08-22 13:43 | 阅读数:491 | 评论:0

本文主要研究Tagged Pointer技术,针对该技术需要解决的问题、以及在实际应用中的价值做一些简单的探讨。
如果你想要更进一步,去挖掘Tagged Pointer是如何实现的,可以参考Friday Q&A 2012-07-27: Let's Build Tagged Pointers和objc源码。
另外,本文中涉及到的示例代码,请在真机iOS设备上测试,因为Tagged Pointer技术针对不同的平台,具体实现细节是有差异的,否则无法得出和本文一致的测试结果。
一、对象的内存
下面我们针对iOS中对象进行一些探究,代码如下,其完整代码见TaggedPointer。
__weak NSNumber *weakNumber;
  __weak NSString *weakString;
  __weak NSDate *weakDate;
  __weak NSObject *weakObj;
  int num = 123;
  
  @autoreleasepool {
    weakObj = [[NSObject alloc] init];
    weakNumber = [NSNumber numberWithInt:num];
    weakString = [NSString stringWithFormat:@"string%d", num];
    weakDate   = [NSDate dateWithTimeIntervalSince1970:0];
  }
  NSLog(@"weakObj is %@", weakObj);
  NSLog(@"weakNumber is %@", weakNumber);
  NSLog(@"weakString is %@", weakString);
  NSLog(@"weakDate is %@", weakDate);
第7行,首先定义了4个__weak***对象,构建了一个autoreleasepool,所以在12行之后,所有__weak修饰的弱引用对象,都会被释放。经过上面分析,我们得出,对象会打印出null。
但是,实际上,我们得到了如下的输出。
TaggedPointer[3570:3928309] weakObj is (null)
TaggedPointer[3570:3928309] weakNumber is 123
TaggedPointer[3570:3928309] weakString is string123
TaggedPointer[3570:3928309] weakDate is Thu Jan  1 08:00:00 1970
可以看到,只有NSObject对应的对象值是null,其他的值,均正常打印。
这是因为NSNumber、NSString、NSDate,在这里采用了Tagged Pointer技术。
二、Tagged Pointer
2.1 Tagged Pointer技术
2.1.1 简介
DSC0000.jpg

2.2.2 未引入Tagged Pointer
DSC0001.jpg

2.2.3 引入Tagged Pointer
DSC0002.jpg

2.2.4 判断是否是Tagged Pointer
DSC0003.jpg

2.2 应用
2.2.1 支持的对象类型
可以从objc源码中找出支持Tagged Pointer 的对象类型,如下:
typedef uint16_t objc_tag_index_t;
enum
{
  OBJC_TAG_NSString      = 2, 
  OBJC_TAG_NSNumber      = 3, 
  OBJC_TAG_NSIndexPath     = 4, 
  OBJC_TAG_NSDate      = 6, 
  ....
};
即针对NSString、NSNumber、NSDate、NSIndexPath这些类型,都支持Tagged Pointer技术。
2.2.2 NSNumber
我们通过NSNumber以及NSString对象来观察Tag+Data的存储形式。
示例代码参见:TaggedPointer
如下所示,我们创建了很多NSNumber对象:
NSNumber *number1 = @1;              //0xb000000000000012
  NSNumber *number2 = @2;              //0xb000000000000022
  NSNumber *number3 = @(0xFFFFFFFFFFFFFFF);    //0x1c0022560
  NSNumber *number4 = @(1.2);            //0x1c0024b80
  int num4 = 5;
  NSNumber *number5 = @(num4);           //0xb000000000000052
  long num5 = 6;
  NSNumber *number6 = @(num5);           //0xb000000000000063
  float num6 = 7;
  NSNumber *number7 = @(num6);           //0xb000000000000074
  double num7 = 8;
  NSNumber *number8 = @(num7);           //0xb000000000000085
  
  //值:0xb000000000000012 0xb000000000000022 0x1c0022560 0x1c0024b80 0xb000000000000052 0xb000000000000063 0xb000000000000074 0xb000000000000085
  NSLog(@"%p %p %p %p %p %p %p %p", number1, number2, number3, number4, number5, number6, number7, number8);
由上表我们得出:

  • 很大的数字,超过Tagged Pointer表示上限的时候,将会转为对象存储,存放在堆上;


  • 如果是含有小数点的浮点数,将会直接以对象方式存储;


  • 其余类型的数字,包括不含小数部分的浮点型和整型都会以Tagged Pointer存储。
并且,针对以上部分,我们整理出Tagged Pointer的存储格式如下,以number1为例:
DSC0004.jpg

2.2.3 NSString
同上面NSNumber的处理逻辑,NSString处理的类似。
NSString *str1 = @"a";                      //0x1049cc248
NSString *str2 = [NSString stringWithFormat:@"a"];        //0xa000000000000611
NSString *str3 = [NSString stringWithFormat:@"bccd"];       //0xa000000646363624
NSString *str4 = [NSString stringWithFormat:@"c"];        //0xa000000000000631
NSString *str5 = [NSString stringWithFormat:@"cdasjkfsdljfiwejdsjdlajfl"];//0x1c02418f0
NSLog(@"%@ %@ %@ %@ %@",
    [str1 class],   //__NSCFConstantString
    [str2 class],   //NSTaggedPointerString
    [str3 class],   //NSTaggedPointerString
    [str4 class],   //NSTaggedPointerString
    [str5 class]);  // __NSCFString
根据以上结果,我们将NSString分类三类:

  • 常量类型:__NSCFConstantString,定义的字符串常量。


  • Tagged Pointer类型:NSTaggedPointerString,通过对象方法创建的短字符串。


  • NSString对象类型:__NSCFString,包括NSString、NSMutableString等创建的字符串对象。
以上,整理如下:
DSC0005.jpg

NSString以Tagged Pointer的存储格式如下:
DSC0006.jpg

2.3 内存管理
DSC0007.jpg


三、一个面试问题的研究
该面试题如下:
DSC0008.jpg


参考
链接
1Friday Q&A 2012-07-27: Let's Build Tagged Pointers
2Tagged Pointer wiki
3NSString retain count -1
4objc源码
示例代码
1TaggedPointer
青山不改,绿水常流!谢谢大家支持。


   
   
   
                        

关注下面的标签,发现更多相似文章