美文网首页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)。

相关文章

  • javascript面向对象解析(一)

    创建对象的方式 json对象方式创建对象 Object方式 声明构造函数方式,创建对象 -- 这种创建对象的方式用...

  • JS笔记-006-JS对象-数字-字符串-日期-数组-逻辑

    JS对象 创建 JavaScript 对象 通过 JavaScript,您能够定义并创建自己的对象。 创建新对象有...

  • 创建对象只是开辟个堆内存那么简单吗?

    java对象 对象的创建 java的对象是在运行时创建的,创建对象的的触发条件有以下几种: 用new语句创建对象,...

  • 对象的创建

    对象的创建 虚拟机遇到一条new指令时,首先去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检...

  • 对象的创建

    一、创建过程 二、重点说明 1.在Java堆中为对象分配内存空间 分配方法 有两种主流方法:指针碰撞;空闲列表。 ...

  • 对象的创建

    创建对象1.工厂模式 2.构造函数模式 3.原型模式 4.组合使用原型模式和构造函数模式 (常见的方式) 5.动态...

  • 对象的创建

    工厂模式 优点:避免创建多个对象时的重复代码问题 缺点:无法解决对象识别问题(不知道一个对象的类型) 构造函数模式...

  • 对象的创建

    1.给对象分配内存 两种方式:1.指针碰撞 2.空闲列表 2.线程安全性问题 3.初始化对象 4.执行构造方法

  • 对象的创建

    1.OC对象是什么? 从源码分析 objc.h objc-private.h: 其中uintptr_t是一个uns...

  • 对象的创建

    JavaScript中的对象实际上是键值对的集合,如何去创建一个对象呢?有以下方法: 字面量创建(Object L...

网友评论

    本文标题:对象的创建

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