4-10-引用计数

当使用alloc、new或者copy创建一个新对象时,新对象的引用计数器默认就是1当一个对象的引用计数器值为0时,对象占用的内存就会被系统回收。换句话说,如果对象的计数器不为0,那么在整个程序运行过程,它占用的内存就不可能被回收,除非整个程序已经退出

正常对象的引用计数 Runtime 会使用一张散列表[SideTable 的类的属性中]来管理引用计数

1.正常对象的引用计数

    NSObject *obj = [[NSObject alloc]init];
    NSLog(@"obj:%lu",[obj retainCount]);

alloc之后引用计数就是 1

    /// 正常的引用计数
    NSNumber *num = [NSNumber numberWithUnsignedLong:238326782365394867];
    NSLog(@"num:%tu",[num retainCount]);
    
    
    /// Tagged Pointer
    NSNumber *num1 = [NSNumber numberWithInt:1];
    NSLog(@"num1: %tu",[num1 retainCount]);

    
    /// __NSCFConstantString -> __NSCFString -> NSMutableString -> NSString -> NSObject
    
    
    /// __NSCFConstantString  一个字符串常量在堆区只分配一个空间
    NSString *str0 = @"1";
    NSLog(@"str0:%tu",[str0 retainCount]);
    NSLog(@"str0:%@",[str0 class]);
    
    
    /// __NSCFConstantString 存在常量区
    NSString *str = [[NSString alloc]initWithString:@"1"];
    NSLog(@"str:%tu",[str retainCount]);
    NSLog(@"str:%@",[str class]);
    
    
    /// __NSCFString  对象
    NSMutableString *str2 = [NSMutableString stringWithFormat:@"%@",@"Copyright © 2019 王景伟. All rights reserved."];
    NSLog(@"str2:%@",[str2 class]);
    NSLog(@"str2:%tu",[str2 retainCount]);

    
    /// __NSCFString  对象
    NSString *str3 = [[NSString alloc]initWithFormat:@"%@",@"Copyright © 2019 王景伟. All rights reserved."];
    NSLog(@"str3:%tu",[str3 retainCount]);
    NSLog(@"str3:%@",[str3 class]);


    /// NSTaggedPointerString  指针
    NSString *str4 = [NSString stringWithFormat:@"%@",@"1"];
    NSLog(@"str4:%@",[str4 class]);
    NSLog(@"str4:%tu",[str4 retainCount]);

2.正常对象的引用计数


32位是没有Tagged Pointer对象的 8 字节
64位  16字节  才有所以一个普通的 iOS 程序,如果没有Tagged Pointer对象,从 32 位机器迁移到 64 位机器中后,虽然逻辑没有任何变化,但这种 NSNumber、NSDate 一类的对象所占用的内存会翻倍。


1.Tagged Pointer专门用来存储小的对象,例如NSNumber, NSDate, NSString。
2.Tagged Pointer指针的值不再是地址了,而是真正的值。所以,实际上它不再是一个对象了,它只是一个披着对象皮的普通变量而已。所以,它的内存并不存储在堆中,也不需要malloc和free。
3.在内存读取上有着3倍的效率,创建时比以前快106倍。


对于 NSString 对象来讲,当非字面值常量的数字,英文字母字符串的长度小于等于 9 的时候会自动成为 NSTaggedPointerString 类型,如果有中文或其他特殊符号(可能是非 ASCII 字符)存在的话则会直接成为 )__NSCFString 类型。

isa 指针

所有对象都有 isa 指针,而Tagged Pointer其实是没有的
由于引入isa的关系 我们不可以直接调用对象的str4->isa;指针

isa 指针数据结构

union isa_t 
{
    isa_t() { }
    isa_t(uintptr_t value) : bits(value) { }
    Class cls;
    uintptr_t bits;
#if SUPPORT_NONPOINTER_ISA
# if __arm64__
#   define ISA_MASK        0x00000001fffffff8ULL
#   define ISA_MAGIC_MASK  0x000003fe00000001ULL
#   define ISA_MAGIC_VALUE 0x000001a400000001ULL
    struct {
        uintptr_t indexed           : 1;
        uintptr_t has_assoc         : 1;
        uintptr_t has_cxx_dtor      : 1;
        uintptr_t shiftcls          : 30; // MACH_VM_MAX_ADDRESS 0x1a0000000
        uintptr_t magic             : 9;
        uintptr_t weakly_referenced : 1;
        uintptr_t deallocating      : 1;
        uintptr_t has_sidetable_rc  : 1;
        uintptr_t extra_rc          : 19;
#       define RC_ONE   (1ULL<<45)
#       define RC_HALF  (1ULL<<18)
    };
# elif __x86_64__
#   define ISA_MASK        0x00007ffffffffff8ULL
#   define ISA_MAGIC_MASK  0x0000000000000001ULL
#   define ISA_MAGIC_VALUE 0x0000000000000001ULL
    struct {
        uintptr_t indexed           : 1;
        uintptr_t has_assoc         : 1;
        uintptr_t has_cxx_dtor      : 1;
        uintptr_t shiftcls          : 44; // MACH_VM_MAX_ADDRESS 0x7fffffe00000
        uintptr_t weakly_referenced : 1;
        uintptr_t deallocating      : 1;
        uintptr_t has_sidetable_rc  : 1;
        uintptr_t extra_rc          : 14;
#       define RC_ONE   (1ULL<<50)
#       define RC_HALF  (1ULL<<13)
    };
# else
    // Available bits in isa field are architecture-specific.
#   error unknown architecture
# endif
// SUPPORT_NONPOINTER_ISA
#endif
};



// Define SUPPORT_NONPOINTER_ISA=1 to enable extra data in the isa field.
#if !__LP64__  ||  TARGET_OS_WIN32  ||  TARGET_IPHONE_SIMULATOR  ||  __x86_64__
#   define SUPPORT_NONPOINTER_ISA 0
#else
#   define SUPPORT_NONPOINTER_ISA 1
#endif

综合看来目前只有 arm64 架构的设备支持,下面列出了 isa 指针中变量对应的含义:

      uintptr_t nonpointer        : 1;  0 表示普通指针 1表示优化过的                                     
      uintptr_t has_assoc         : 1;    是否设置过关联对象                                  
      uintptr_t has_cxx_dtor      : 1;  是否有C++的析构函数                                     
      uintptr_t shiftcls          : 33; 存储 class 和 mate_class的内存地址
      uintptr_t magic             : 6;                                      
      uintptr_t weakly_referenced : 1;     是否被弱指针指向过                                  
      uintptr_t deallocating      : 1;         是否正在被释放                              
      uintptr_t has_sidetable_rc  : 1;     引用计数是否过大无法存储在isa中  没有的话 存储在 SideTable中                           
      uintptr_t extra_rc          : 19引用计数减1的值

参考:https://www.cnblogs.com/xiaosong666/p/5045494.html

你可能感兴趣的:(4-10-引用计数)