iOS-对象的本质-一个OC对象占多少内存

我们平常敲的Objective-C代码,底层实现其实是C/C++代码.那么一个OC对象占用多少内存.

iOS开发中Objective-C和swift用的是Clang/LLVM来编译的.
使用的clang编译器编译成cpp,xcodebuild负责将OC/Swift工程编译成xxx.app,xcrun负责给xxx.app签名并打包成xxx.ipa
 

#import <Foundation/Foundation.h>
int main(int argc, char * argv[]) {
    @autoreleasepool {
        NSObject *obj = [[NSObject alloc] init];
        NSLog(@"hello world!");     
    }
    return 0;
}

通过clang编译器编译成cpp,执行

clang -rewrite-objc main.m -o main.cpp

我们也可以指定iphoneos/arm64,执行

 xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main64.cpp

生成main64.cpp,其中main函数的执行代码转换成C/C++的代码:

#pragma clang assume_nonnull end

int main(int argc, char * argv[]) {
    /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool;
        
        /**
         这里我们可以看到objc_msgSend(id,SEL)

         @param NSObject 类型是NSObject
         @return 返回类型是NSObject
         */
        NSObject *object = ((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("NSObject"), sel_registerName("alloc")), sel_registerName("init"));
        NSLog((NSString *)&__NSConstantStringImpl__var_folders_9d_y4q9htmj3q17ljhpchdzt5vc0000gp_T_main_2c6acf_mi_0);
    }
    return 0;
}

在这里我们看到熟悉的面孔__autoreleasepool和objc_msgSend,一个是自动释放池,一个是消息传递
自动释放池内部用的是双向链表,通过标记卫士来删除
 

/**
 这里我们看到push入栈生成atautoreleasepoolobj
           pop出栈生成atautoreleasepoolobj
 */
struct __AtAutoreleasePool {
  __AtAutoreleasePool() {atautoreleasepoolobj = objc_autoreleasePoolPush();}
  ~__AtAutoreleasePool() {objc_autoreleasePoolPop(atautoreleasepoolobj);}
  void * atautoreleasepoolobj;
};

接着我们看到

//OC转成C++的代码
struct NSObject_IMPL {
	Class isa;
};
typedef struct objc_class *Class;
struct objc_object {
    Class _Nonnull isa __attribute__((deprecated));
};

// runtime.h
struct objc_class {
    Class _Nonnull isa  OBJC_ISA_AVAILABILITY;

#if !__OBJC2__
    Class _Nullable super_class                              OBJC2_UNAVAILABLE;
    const char * _Nonnull name                               OBJC2_UNAVAILABLE;
    long version                                             OBJC2_UNAVAILABLE;
    long info                                                OBJC2_UNAVAILABLE;
    long instance_size                                       OBJC2_UNAVAILABLE;
    struct objc_ivar_list * _Nullable ivars                  OBJC2_UNAVAILABLE;
    struct objc_method_list * _Nullable * _Nullable methodLists                    OBJC2_UNAVAILABLE;
    struct objc_cache * _Nonnull cache                       OBJC2_UNAVAILABLE;
    struct objc_protocol_list * _Nullable protocols          OBJC2_UNAVAILABLE;
#endif

} OBJC2_UNAVAILABLE;

可以看到我们回到了NSObject就是一个对象,就是一个结构体指针
执行过程:objc_getClass-->(objc_class *)objc_getClass-->objc_class结构体
也就是class就是一个指针,指针在32位是4字节,64位是8字节

#import <Foundation/Foundation.h>
#import <objc/runtime.h>
#import <malloc/malloc.h>
int main(int argc, char * argv[]) {
    @autoreleasepool {
        NSObject *obj = [[NSObject alloc] init];
        NSLog(@"hello world!");
        //获得NSobject对象实例成员变量占用的大小 ->8
        size_t size = class_getInstanceSize(obj.class);
        //获取NSObjet指针的指向的内存大小 ->16
        size_t size2 = malloc_size((__bridge const void *)(obj));
        NSLog(@"size;%zu size2:%zu",size,size2);
        
    }
    return 0;
}

执行结果:size;8 size2:16

也就是说obj就是一个指向class的指针,如果机器是64为, obj指针是8字节,指针指向的内存大小为16字节.
Person添加两个成员变量
 

#import <Foundation/Foundation.h>
#import <objc/runtime.h>
#import <malloc/malloc.h>
@interface Person : NSObject
{
    @public
    int _age;
    int _no;
}
@end
int main(int argc, char * argv[]) {
    @autoreleasepool {
//        NSObject *obj = [[NSObject alloc] init];
//        NSLog(@"hello world!");
        Person *obj = [[Person alloc] init];
        obj->_age = 15;
        obj->_no  = 14;
       //获取NSObject对象实例成员变量占用大小  8
        size_t size = class_getInstanceSize(obj.class);
       //获取NSObject指针指向的内存大小是   16
        size_t size2 = malloc_size((__bridge const void *)(obj));
        NSLog(@"size;%zu size2:%zu",size,size2);
    
    }
    return 0;
}
//转为C++
struct Person_IMPL {
	struct NSObject_IMPL NSObject_IVARS;//8bytes
	int _age;  //4bytes
	int _no;   //4bytes
};
输出结果:size;16 size2:16

实例对象其实是结构体,占用内存是16倍数,实例对象大小不受方法影响,受实例成员变量多少影响
参考:https://juejin.im/post/5d15887ee51d45108126d28d

发布了36 篇原创文章 · 获赞 16 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/qq_28551705/article/details/99664908