likes
comments
collection
share

窥探窥探OC对象本质和内存使用

作者站长头像
站长
· 阅读数 30

      写过iOS开发的同学肯定都知道NSObject这个类,他是一切OC对象的始祖,号称“万类之父”。跟其他现代编程语言(如Java,拍黄片、Go等)不一样,OC的对象大多是以NS开头,这源于Jobs在1985年离开Apple之后创立的NEST STEP公司所开发的操作系统。后来Jobs回归Apple,这一操作系统的精髓也被沿用到MAC OS X(也就是现在的macOS)、iOS、watchOS、tvOS,这些系统都是BSD UNIX-386BSD家族成员,Android、Linux则是UNIX-Like家族成员,甚至将来的carOS,这一品牌式命名一直严用到如今。今天我们就来窥探一下这个万类之父到底是什么东西。

      要了解NSObject的本质,我们就先从Apple官方文档先一探究竟啦,在Xcode按住它点击看下图,当然这是swift的声明,这不是重点,看到没,root class!但这只是描述性意思。面试官问你OC本质,你总不能回答它是很多类的父类吧。

窥探窥探OC对象本质和内存使用

      再点进去看看

@interface NSObject <NSObject> {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-interface-ivars"
    Class isa  OBJC_ISA_AVAILABILITY;
#pragma clang diagnostic pop
}

看源码声明,首先NSObject遵循《NSObject》这一协议,里面包含一个isa指针,上下2句push、pop则是汇编语言里入栈和出栈的意思,也就是能理解isa的本质就能知道NSObject的本质啦。从源码中我们看到isa是一个Class类型,也就是类,所以问题可以回到OC类的本质是什么?那我们再点住Class进去看

#if !OBJC_TYPES_DEFINED
/// An opaque type that represents an Objective-C class.
typedef struct objc_class *Class;

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

/// A pointer to an instance of a class.
typedef struct objc_object *id;
#endif

这是官方对Class的声明,C++语法,struct的声明,这是一个结构体,也就是说 OC对象的本质就是结构体

在arm64架构之前,isa就是纯粹的指针地址,当时一个OC对象只占用8个字节的内存地址,但是在arm64架构之后,isa就不单单是一个指针地址的了,它还包括引用计数、释放池、dealloc等等信息,所以arm64架构里,一个OC对象在创建时会占用16个字节,这个结论我们可以通过XCode来验证一下。代码如下:

NSObject *object = [[NSObject alloc]init];
size_t objc_size = malloc_size((__bridge const void *)(object));
NSLog(@"object对象占用的字节 = %zd",objc_size);

结果为

窥探窥探OC对象本质和内存使用 再八卦一下,一个UIViewController创建的时候会占用多少内容?我们直接看运行结果吧。代码如下:

UIViewController *controller = [[UIViewController alloc]init];   
size_t controller_size = malloc_size((__bridge const void *)(controller));
NSLog(@"UIViewController实例对象占用的内存 = %zd",controller_size);

结果为848

窥探窥探OC对象本质和内存使用

其他研究这些看似枯燥的东西是个很有意思的事情,读者如果有兴趣可以再看看一个对象在创建了分类、扩展、属性、方法、代理等等之后的内存变化。能对这些东西有研究,你在日常工作中就一定会注意该用什么解决方案来做到APP的整理性能最佳。

转载自:https://juejin.cn/post/6844904026027343885
评论
请登录