美文网首页精华runtimeiOS程序猿
runtime使用篇: class_getInstanceSiz

runtime使用篇: class_getInstanceSiz

作者: 缔造福地 | 来源:发表于2016-12-17 23:17 被阅读740次
    size_t class_getInstanceSize(Class cls)

    说明:该函数的作用是获取类的实例所占用内存的大小(单位是字节)

    1. 以 NSObject 类为例,代码示例如下:
    size_t size = class_getInstanceSize([NSObject class]);
    NSLog(@"%zu", size);
    

    在模拟器iPhone 4s和iPhone 5上运行打印结果是4,在iPhone 5s及之后的机型运行打印结果是8。

    分析:Objective-C中,每个对象内部都有一个 isa 指针,指向该对象的类;一个类从另一角度来说也是一个对象,类也有一个 isa 指针,指向该类的元类。
    因此上述代码打印出的结果,就是 NSObject 实例中 isa 指针所占用的字节数。

    至于不同机型打印结果不同,是因为目标系统位数的不同:iPhone 5s开始使用了64位的处理器及系统;和使用Xcode的电脑系统位数无关(iOS开发)。一个指针所占用的字节数在32位系统上为4字节,在64位系统上为8字节。其他基本数据类型在32位和64位系统中所占用的字节数也有所差异:

    32位系统下:
    char a; // 1
    short b; // 2
    int c; // 4
    long d; // 4
    float e; // 4
    long long f; // 8
    double g; // 8
    int *h; // 4
    
    64位系统下:
    char a; // 1
    short b; // 2
    int c; // 4
    long d; // 8
    float e; // 4
    long long f; // 8
    double g; // 8
    int *h; // 8
    

    可见32位和64位系统中只有 long指针 类型所占用的字节数不同。

    2. 以其他类为例(以下均在64位的目标系统上进行测试)

    (1). 自定义类 Person 类及代码示例如下

    // Person.h
    @interface Person : NSObject
    /** name */
    @property (nonatomic, copy) NSString *name;
    /** age */
    @property (nonatomic, assign) int age;
    @end
    
    // Person.m
    @interface Person ()
    {
        NSString *childhoodName;
    }
    @end
    
    // ViewController.m
    size_t size = class_getInstanceSize([Person class]);
    NSLog(@"%zu", size);
    

    打印结果为32,这是内部的 isa 指针和两个 NSString 指针、一个 int 类型一共占用的字节数。刚才测试的 int 类型在64位系统下所占字节数为4,为什么现在和3个指针所占用的字节数加起来是32呢?这是因为『字节对齐』的原因(译文1译文2原文)。

    (2). 自定义类 LittlePerson 类及代码示例如下
    当一个类继承其他类时,会继承此类的所有属性和实例变量

    // LittlePerson.h
    @interface LittlePerson : Person
    /** 学校 */
    @property (nonatomic, copy) NSString *school;
    /** 玩具 */
    @property (nonatomic, strong) NSArray *toys;
    /** 书 */
    @property (nonatomic, assign) short bookCount;
    @end
    
    // LittlePerson.m
    @interface LittlePerson ()
    @end
    
    // ViewController.m
    size_t size = class_getInstanceSize([LittlePerson class]);
    NSLog(@"%zu", size);
    

    打印结果为56。

    要注意的是 class_getInstanceSize 函数和 sizeof() 并不等同

    size_t size = class_getInstanceSize([UIViewController class]);
    NSLog(@"InstanceSize: %zu", size);
    
    UIViewController *vc = [[UIViewController alloc] init];
    NSLog(@"sizeof: %ld", sizeof(vc));
    NSLog(@"sizeof: %ld", sizeof([UIViewController class]));
    

    打印结果如下:

    runtime[57907:5849922] InstanceSize: 696
    runtime[57907:5849922] sizeof: 8
    runtime[58021:5856762] sizeof: 8
    
    3. 从字节对齐看苹果对内存的优化

    Person 类中增加几个属性和实例变量,其中标号为数字1、2、3的是上述代码中已有的,变量名为单个字母(a--h)的是新增加的。代码示例如下:

    // Person.h
    @interface Person : NSObject
    /** name */
    @property (nonatomic, copy) NSString *name; // 1
    /** age */
    @property (nonatomic, assign) int age; // 2
    /** other */
    @property (nonatomic, copy) NSString *a;
    @property (nonatomic, assign) int b;
    @property (nonatomic, assign) char *c;
    @property (nonatomic, assign) short d;
    @end
    
    // Person.m
    @interface Person ()
    {
        NSString *childhoodName; // 3
        short e;
        char f[8];
        NSString *g;
        int h;
    }
    @end
    
    // ViewController.m
    size_t size = class_getInstanceSize([Person class]);
    NSLog(@"InstanceSize: %zu", size);
    

    我们先猜想一下打印结果。通过学习刚才链接中的字节对齐的知识,可以推测结果是96,我们先不公布打印结果,先按正常的字节对齐看看96是否正确。在 ViewController.m 中增加以下代码,一一对应 Person 实例中的属性和实例变量:

    struct people {
        char *isa;
        char *name;
        int age;
        char *a;
        int b;
        char *c;
        short d;
        char *childhoodName;
        short e;
        char f[8];
        char *g;
        int h;
    };
    
    struct people p;
    NSLog(@"sizeof:%ld", sizeof(p));
    

    本次打印结果为96,对字节对齐的知识有所掌握😃
    再回到刚才 Person 实例,打印结果如下:

    runtime[58897:5911521] InstanceSize: 80
    

    推测的并不正确。
    如果手动对属性和成员变量『共同』重排进行优化,对应的 people 结构体如下:

    struct people {
        char *isa;
        char *name;
        char *a;
        char *c;
        char *childhoodName;
        char *g;
        char f[8];
        int age;
        int b;
        int h;
        short d;
        short e;
    };
    
    struct people p;
    NSLog(@"sizeof:%ld", sizeof(p));
    

    此时打印结果为72,和 Person 实例所占用内存的大小仍不一样。
    现在手动对属性和成员变量『分别』重排进行优化,对应的 people 结构体如下:

    struct people {
        char *isa;
        char *name;
        char *a;
        char *c;
        int age;
        int b;
        short d;
        
        char *childhoodName;
        char *g;
        char f[8];
        int h;
        short e;
    };
    
    struct people p;
    NSLog(@"sizeof:%ld", sizeof(p));
    

    此时打印结果为80,和 Person 实例所占用内存的大小相同。可见:
    苹果会自动对属性和成员变量进行分别重排从而优化内存
    这一切不需要我们手动去优化,大大地节省了程序员的时间。
    很早之前就听说苹果会变动一些代码的顺序进行优化,今天总算知道会出现在哪里了😃

    相关文章

      网友评论

        本文标题:runtime使用篇: class_getInstanceSiz

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