MST

星途 面试题库

面试题:Objective-C对象创建与销毁过程中的runtime机制深度剖析

在Objective-C对象的创建与销毁过程中,runtime起到了关键作用。请详细说明runtime是如何参与对象的创建,包括类的加载、元类的作用等,以及在对象销毁时runtime所执行的底层操作。同时,如何利用runtime机制优化对象创建与销毁的性能?
35.6万 热度难度
编程语言Objective-C

知识考点

AI 面试

面试题答案

一键面试

对象创建过程中runtime的作用

  1. 类的加载

    • 在程序启动时,runtime会进行类的加载。它会从可执行文件和动态链接库中读取类的相关信息,包括类的定义、属性、方法列表等。例如,objc_class结构体包含了类的基本信息,runtime通过解析这些数据结构来加载类。
    • 类的加载过程还涉及到类的依赖关系处理,runtime会确保父类先被加载,然后再加载子类,以保证类的继承体系完整。比如,若有一个SubClass继承自SuperClass,runtime会先加载SuperClass,再加载SubClass
  2. 元类的作用

    • 元类(meta - class)在runtime中是用于存储类方法的地方。每个类都有一个对应的元类。例如,对于一个普通类MyClassMyClass的实例方法存储在MyClass类对象的methodLists中,而MyClass的类方法(如+ (void)classMethod)则存储在MyClass对应的元类的methodLists中。
    • 元类在消息发送机制中也起着关键作用。当向一个类发送类方法消息时,runtime首先会在该类对应的元类中查找方法实现。例如,当执行[MyClass classMethod]时,runtime会到MyClass的元类中查找classMethod的实现。
  3. 对象创建的具体过程

    • 当使用alloc方法创建对象时,runtime首先会根据类的信息计算对象所需的内存大小。这包括实例变量占用的空间以及一些额外的开销(如对象的引用计数等)。
    • 然后,runtime会向系统申请一块足够大小的内存来存储对象。例如,对于一个包含几个intNSString *类型实例变量的类,runtime会计算出这些变量以及其他必要信息总共需要的内存字节数,并分配相应的内存。
    • 接着,runtime会对分配的内存进行初始化,将对象的引用计数设置为1(在ARC环境下有不同的处理方式,但基本概念类似),并将实例变量初始化为默认值(如int类型初始化为0,指针类型初始化为nil)。最后返回一个指向该对象内存地址的指针。

对象销毁时runtime的底层操作

  1. 引用计数处理
    • 在MRC(手动引用计数)环境下,当对象的引用计数减为0时(通过release方法),runtime会开始销毁对象。在ARC(自动引用计数)环境下,编译器会在适当的位置插入引用计数操作代码。
    • runtime会检查对象的引用计数是否为0。如果为0,它会释放对象占用的内存。例如,对于一个NSString对象,当引用计数变为0时,runtime会释放该NSString对象所占用的堆内存。
  2. 调用析构函数
    • 在释放对象内存之前,runtime会调用对象的析构函数(dealloc方法)。在dealloc方法中,可以进行一些资源清理操作,如释放分配的文件句柄、关闭网络连接等。例如,如果一个对象在初始化时打开了一个数据库连接,在dealloc方法中需要关闭这个数据库连接。
    • dealloc方法会递归地调用父类的dealloc方法,以确保整个继承体系中的资源都能被正确清理。例如,若SubClass继承自SuperClassSubClassdealloc方法在执行完自身的清理操作后,会调用[super dealloc]来清理SuperClass中的资源。

利用runtime机制优化对象创建与销毁的性能

  1. 对象创建优化
    • 缓存重用:可以利用runtime的缓存机制。例如,runtime有方法缓存,对于频繁调用的方法,会将其缓存起来。在对象创建时,可以考虑复用一些常用的对象结构或者缓存已创建的对象。比如,在一个频繁创建和销毁NSString对象的场景中,可以使用NSMutableString并通过setString:方法来复用对象,而不是每次都创建新的NSString对象。
    • 减少不必要的属性:通过runtime查看类的属性列表,减少对象中不必要的属性。属性越多,对象创建时计算内存大小和初始化的开销就越大。例如,如果一个类中有一些很少使用的属性,可以考虑将其移除或者采用懒加载的方式。
  2. 对象销毁优化
    • 及时释放资源:在dealloc方法中,确保及时释放资源。避免在dealloc方法中进行复杂的操作,因为dealloc方法执行时,对象已经处于即将被销毁的状态,过多复杂操作可能影响性能。例如,如果对象持有一个大的图片数据,在dealloc方法中应尽快释放该图片占用的内存。
    • 优化引用计数管理:在MRC环境下,准确管理引用计数,避免过度释放或提前释放。在ARC环境下,虽然编译器自动管理引用计数,但了解其原理有助于优化代码结构。例如,合理使用weakstrong等修饰符,避免循环引用导致对象无法及时销毁。如果存在循环引用,对象的引用计数永远不会变为0,从而无法被销毁,造成内存泄漏。通过使用weak修饰符打破循环引用,可以使对象在不再被强引用时及时被销毁。