返回

OC对象原理探索:深入剖析OC对象内存分配与管理

IOS

前言

在上一篇文章中,我们按照源码分析了一下alloc的调用流程,大致如下:

objc_msgSend(objc_getClass("NSObject"), sel_registerName("alloc"))

现在我们在objc源码中,再做一次分析alloc具体是如何调用C++底层的函数的

alloc的C++实现

objc源码中的alloc函数定义在objc-runtime-new.mm文件中:

id objc_msgSend(Class cls, SEL op, ...)
{
    // ... 省略其他代码 ...
    
    if (cls == nil) {
        @throw([NSInvalidArgumentException exceptionWithName:@"NSObject+Nil" reason:@"nil class" userInfo:nil]);
    }
    
    if (op == nil) {
        @throw([NSInvalidArgumentException exceptionWithName:@"NSObject+Nil" reason:@"nil selector" userInfo:nil]);
    }
    
    // ... 省略其他代码 ...
    
    struct objc_super super;
    // ... 省略其他代码 ...
    
    id (*msgSendTyped)(id, SEL, ...) = (id (*)(id, SEL, ...))objc_msgSend_stret;
    
    // ... 省略其他代码 ...
    
    return (*msgSendTyped)(receiver, op, &super, ...);
}

从这段代码中,我们可以看到alloc函数最终调用了objc_msgSend_stret函数,该函数定义在objc-msg-send.mm文件中:

extern "C" id objc_msgSend_stret(id self, SEL op, ...)
{
    // ... 省略其他代码 ...
    
    // 获取方法的实现
    IMP imp = class_getMethodImplementation(cls, op);
    
    // ... 省略其他代码 ...
    
    // 调用方法的实现
    id result = imp(self, op, ...);
    
    // ... 省略其他代码 ...
    
    return result;
}

通过以上分析,我们可以得知alloc函数最终调用了class_getMethodImplementation函数获取方法的实现,然后调用该实现来分配对象。

ARC和MRC下的内存管理

在ARC(Automatic Reference Counting)下,内存管理是自动进行的,编译器会自动跟踪对象的引用计数,并在引用计数为0时释放对象。

在MRC(Manual Reference Counting)下,内存管理需要手动进行,开发人员需要自己管理对象的引用计数,并在不需要对象时手动释放对象。

ARC下的内存管理

在ARC下,编译器会自动跟踪对象的引用计数,并在引用计数为0时释放对象。例如:

// 创建一个对象
NSObject *obj = [[NSObject alloc] init];

// ... 省略其他代码 ...

// 对象不再需要,引用计数为0,编译器自动释放对象
obj = nil;

在ARC下,我们不需要手动管理对象的引用计数,编译器会自动完成这项工作。

MRC下的内存管理

在MRC下,内存管理需要手动进行,开发人员需要自己管理对象的引用计数,并在不需要对象时手动释放对象。例如:

// 创建一个对象
NSObject *obj = [[NSObject alloc] init];

// ... 省略其他代码 ...

// 对象不再需要,需要手动释放对象
[obj release];

在MRC下,我们需要自己管理对象的引用计数,并在不需要对象时手动释放对象。

总结

本文深入探索了OC对象内存分配与管理原理,从源码分析alloc的调用流程,揭秘ARC和MRC下的内存管理机制,全面解析OC对象的创建、销毁和内存管理细节,帮助你深入理解OC对象的底层实现。