美文网首页Object
对象的创建

对象的创建

作者: 小溜子 | 来源:发表于2020-08-25 15:31 被阅读0次

    1.OC对象是什么?

    从源码分析

    typedef struct objc_class *Class;
    typedef struct objc_object *id;
    

    objc.h

    /// Represents an instance of a class.
    // objc_object 的声明
    struct objc_object {
        Class _Nonnull isa  OBJC_ISA_AVAILABILITY;
    };
    

    objc-private.h:

    // objc_object 的实现
    struct objc_object {
    private:
        isa_t isa;
    以下是一些函数,省略
    
    objc-private.h:
    ...
    }
    
    // isa_t的定义,一个联合体,值为cls或者bits
    union isa_t {
        isa_t() { }
        isa_t(uintptr_t value) : bits(value) { }
    
        Class cls;
        uintptr_t bits;
    #if defined(ISA_BITFIELD)
        struct {
            ISA_BITFIELD;  // defined in isa.h
        };
    #endif
    };
    

    其中uintptr_t是一个unsigned long类型,定义如下

    typedef unsigned long           uintptr_t;
    

    objc-runtime-new.h :

    struct objc_class : objc_object {
        // Class ISA;
        Class superclass;
        cache_t cache;             // formerly cache pointer and vtable
        class_data_bits_t bits;    // class_rw_t * plus custom rr/alloc flags
        以下是一些函数,省略
        ...
    }
    
    • 结合源码我们知道,OC对象是objc_object的结构体,包含了一个联合体isa_t,isa_t的值可能是cls或者bits,cls是指针类型,占8字节,bits是unsigned long类型,占8字节,由此得到isa占大小为8字节。
    • 另外根据源码,我也知道了类是一个objc_class的结构体,objc_class继承自objc_object,说明类也是一个对象。

    2.OC对象包含什么?

    我们已经知道了OC对象是一个objc_object类型的结构体,里面包含一个联合体isa,那么isa究竟是什么?

    • 总结概述,isa_t联合体有3个成员,3个成员cls\bit\匿名结构体s共同占用8字节的内存空间,8个字节空间存储着对象、类等的一些信息,通过匿名结构体里面的位域,可以获取到这些信息。

    3.对象所占的内存空间

    关于对象所占的内存空间,严格上讲是对象的指针所指向的结构体所占的内存空间。
    系统提供了2个api获取有关对象内存空间的大小,我们看看如下例子:

    创建Person继承NSObject:
    Person.h

    @interface Person : NSObject
    
    @end
    

    Person.m

    @implementation Person
    
    @end
    

    我们在main.m中添加

    Person *person = [Person alloc];
    FHLog(@"class_getInstanceSize: is %ld ",class_getInstanceSize([person class]));
    FHLog(@"malloc_size:%ld ",malloc_size((__bridge const void*)person));
    

    log打印如下:
    class_getInstanceSize: is 8
    malloc_size:16
    class_getInstanceSize和malloc_size究竟代表什么呢?

    • class_getInstanceSize输出的是对象实例经过内存对齐后的占用的大小,
    • malloc_size输出的是对象实际占用内存空间的大小,即系统实际分配给对象的内存空间的大小。

    3.1class_getInstanceSize

    从源码分析,相关的源码如下:

    size_t class_getInstanceSize(Class cls)
    {
        if (!cls) return 0;
        return cls->alignedInstanceSize();
    }
    
    // Class's ivar size rounded up to a pointer-size boundary.
    // 类的实例对象的成员变量的大小
    uint32_t alignedInstanceSize() {
        return word_align(unalignedInstanceSize());
    }
    
    // 相当于(x+7)>>3 <<3,保证>=8且按8的倍数对齐
    static inline uint32_t word_align(uint32_t x) {
        return (x + WORD_MASK) & ~WORD_MASK;
    }
    
    #   define WORD_MASK 7UL
    
    // May be unaligned depending on class's ivars.
    // 根据类的实例变量可能会进行内存对齐处理
    uint32_t unalignedInstanceSize() {
        assert(isRealized());
        return data()->ro->instanceSize;
    }
    
    • 这里说明一下data()->ro->instanceSize,data()是objc_class的bits.data()data()->ro->instanceSize的大小的在编译的时候就已经确定了,和类中成员变量以及对齐系数有关,默认是8的倍数。 由于unalignedInstanceSize() 可能受对齐系数的影响,得到的值可能不是8的倍数,需要word_align()保证返回的值为8的倍数。
    • 我们的Person虽然没定义成员变量,但是Person继承自NSObject,实际上是一个objc_Objec类型的结构体,但是里面包含一个联合体类型的isa,isa前面我们分析,所占大小为8字节,所以输出class_getInstanceSize: is 8。

    3.2mallocSize

    • malloc_size返回的是指针所指向的内存空间所占的大小,即系统实际分配的大小。
      在第一篇我们分析alloc流程时候,在_class_createInstanceFromZone里有
    id
    _class_createInstanceFromZone(Class cls, size_t extraBytes, void *zone, 
                                  bool cxxConstruct = true, 
                                  size_t *outAllocatedSize = nil)
    {
    .....
        // 1.根据extraBytes计算对象的内存空间大小
        size_t size = cls->instanceSize(extraBytes);
        ···
        // 2.根据计算的size为obj申请分配内存
        obj = (id)calloc(1, size);
    .....
    }
    

    其中cls->instanceSize实现如下:

    size_t instanceSize(size_t extraBytes) {
        size_t size = alignedInstanceSize() + extraBytes;
        // CF requires all objects be at least 16 bytes.
        if (size < 16) size = 16;
        return size;
    }
    
    • extraBytes通常为0,cls->instanceSize返回值按8字节对齐,并且保证最小值为16,所以size最小为16。
    • 调用calloc函数向系统申请分配内存,calloc的对输入的size按16字节对齐方式开辟内存空间开辟大小:size+15>>4<<4,保证size>=16且为16的倍数(calloc的源码实现在libmalloc项目里,这里暂不深入libmalloc里中calloc源码实现)。
    • 由于Person只包含一个联合体isa,因此malloc_size:16。

    我们为改动Person测试如下:
    Person.h

    @interface Person : NSObject
    
    @property (nonatomic, assign) int age;
    @property (nonatomic, assign) int height;
    
    @end
    

    输出:
    class_getInstanceSize: is 16
    malloc_size:16

    Person.h

    @interface Person : NSObject
    
    @property (nonatomic, assign) int age;
    @property (nonatomic, assign) int height;
    @property (nonatomic, assign) bool isHealthy;
    
    @end
    

    输出:
    class_getInstanceSize: is 24
    malloc_size:32

    与我们的分析一致。

    • 总结:OC中的继承自NSObject的对象所占内存空间大小,首先根据成员变量和内存对齐规则,得到实例变量所占的空间大小size,然后调用calloc输入size,按16字节对齐最后得到实际开辟的内存空间的大小。

    4.#总结

    • OC对象是什么?
      答:OC对象是一个objc_object类型的结构体
    • OC对象包含什么?
      答:OC对象是一个objc_object类型的结构体,包含一个联合体类型的isa
    • OC对象所占内存大小的的计算实现?
      答:OC对象实际占用内存大小(即系统分配的内存大小),先根据对象的成员属性按8字节计算得到对象成员对齐大小(alignmentSize),再把alignmentSize按照16字节对齐计算得到对象分配内存大小(allocSize)。

    相关文章

      网友评论

        本文标题:对象的创建

        本文链接:https://www.haomeiwen.com/subject/krqzjktx.html