美文网首页
iOS 两个容易混淆的函数:class_getInstanceS

iOS 两个容易混淆的函数:class_getInstanceS

作者: 笔头还没烂 | 来源:发表于2023-04-08 17:49 被阅读0次
    1. iOS 两个容易混淆的函数:class_getInstanceSize & malloc

      • 示例代码如下:

        #import <Foundation/Foundation.h>
        #import <objc/runtime.h>
        #import <malloc/malloc.h>
        
        struct NSObject_IMPL
        {
            Class isa;
        };
        
        struct Person_IMPL{
            struct NSObject_IMPL NSOBJECT_IVARS;
            int _age;
            int _height;
            int _no;
        };
        
        @interface Person : NSObject
        {
            //年龄
            int _age;
            //身高
            int _height;
            //学号
            int _no;
        }
        @end
        
        @implementation Person
        
        @end
        
        int main(int argc, char * argv[]) {
        
            @autoreleasepool {
                // Setup code that might create autoreleased objects goes here.
                NSObject *obj = [[Person alloc] init];
                /**
                sizeof 是针对传入的类型作计算
                sizeof 是运算符,不是函数,编绎之后就能立马确定结果。编绎后根据传入的类型能算出结果,随后类似宏定义编绎后替换源代码一样,将结果与 sizeof 表达式进行替换。
                 */
                NSLog(@"%zd",sizeof(struct Person_IMPL));
                size_t size1 = class_getInstanceSize([Person class]);
                size_t size2 =  malloc_size((__bridge const void *)(obj));
                NSLog(@"%zd",size1);
                NSLog(@"%zd",size2);
            }
            return 0;
        }
        

        输出结果:

        24
        24
        32

        查看苹果的相关源码(源码地址:https://github.com/apple-oss-distributions/libmalloc/tags),相关源码如下:

        1. 在 malloc.c 文件中搜索 “calloc(size” 可得:

          void *
          calloc(size_t num_items, size_t size)
          {
              return _malloc_zone_calloc(default_zone, num_items, size, MZ_POSIX);
          }
          
        2. 跳转 _malloc_zone_calloc 方法,可得:

          MALLOC_NOINLINE
          static void *
          _malloc_zone_calloc(malloc_zone_t *zone, size_t num_items, size_t size,malloc_zone_options_t mzo)
          {
              if (zone == default_zone && !lite_zone) {
                  // Eagerly resolve the virtual default zone to make the zone version
                  // check accurate
                  zone = malloc_zones[0];
              }
          
              if (os_unlikely(malloc_instrumented || malloc_check_start ||
                          malloc_logger || zone->version < 13)) {
                  return _malloc_zone_calloc_instrumented_or_legacy(zone, num_items,     size, mzo);
              }
          
              // zone versions >= 13 set errno on failure so we can tail-call
              return zone->calloc(zone, num_items, size);
          }
          
        3. /* Buckets sized {16, 32, 48, ..., 256} */

        小结:

        1. class_getInstanceSize 返回的实际上就是结构体所有成员变量的大小,通过上面代码的测试,它的作用与 sizeof 计算一个结构体所有成员大小的结果是一致的。

        2. malloc 是通过 calloc(1,size) 方法最终算出需要给对象分配多大的内存空间。此处传入的 size 通过源码也能发现,实际上就是等于 class_getInstanceSize 返回的大小。而他们最终分配的内存空间大小差异就在于:malloc 还多了 calloc 方法这一层的处理。

        3. malloc 是在堆内存中进行操作,堆内存的内存分配也是遵循了内存对齐的原则。这里跟 bucketSize 的大小有关,即分配的内存大小必须是16的倍数。因此,传入的 size 是24,经过 calloc 这一层处理之后,返回的就是 32.

    2. 结论:

      1. 创建一个实例对象,至少需要多少内存?

        #import <objc/runtime.h>
        class_getInstanceSize([NSObject class]);
        
      2. 创建一个实例对象,实际上分配了多少内存?

        #import <malloc/malloc.h>
        malloc_size((__bridge const void *)obj);
        

    相关文章

      网友评论

          本文标题:iOS 两个容易混淆的函数:class_getInstanceS

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