返回

揭秘OC对象底层原理(1)——alloc剖析与对象地址对比

IOS

什么是alloc?alloc方法在OC对象的生命周期中扮演着至关重要的角色,它是对象创建过程的起点,负责分配必要的内存空间并初始化对象。alloc方法的具体行为可以从以下几个方面来剖析:

1. 内存分配:
alloc方法首先调用calloc函数,为新对象分配一块连续的内存空间,并将其返回给调用者。calloc函数的作用是分配指定数量的内存块,并将其全部初始化为0。分配的内存块大小由对象的实例变量大小决定,即class_getInstanceSize函数的返回值。

2. 对象布局:
分配的内存块被划分为两个部分:对象头和实例变量。对象头位于内存块的开头,它包含一些与对象相关的重要信息,如对象的类信息、引用计数、同步锁等。实例变量紧随对象头之后,它们是对象的实际数据成员。

3. 对象初始化:
内存分配完成后,alloc方法会对对象进行初始化。初始化过程包括调用对象的构造函数,并对实例变量进行必要的赋值。构造函数负责对象的初始化,它会在对象创建时自动调用。

在了解了alloc方法的基本原理后,我们可以进一步探究OC对象在内存中的布局和存储方式。通过以下代码片段,我们可以分别打印出三个对象的内容内存地址对象指针地址

#import <Foundation/Foundation.h>

@interface Person : NSObject
{
    NSString *_name;
    int _age;
}

- (instancetype)initWithName:(NSString *)name age:(int)age;
@end

@implementation Person

- (instancetype)initWithName:(NSString *)name age:(int)age
{
    self = [super init];
    if (self) {
        _name = name;
        _age = age;
    }
    return self;
}

@end

int main() {
    Person *person1 = [[Person alloc] initWithName:@"John" age:20];
    Person *person2 = [[Person alloc] initWithName:@"Mary" age:25];
    Person *person3 = [[Person alloc] initWithName:@"Bob" age:30];

    NSLog(@"person1: %p %p %@", person1, &person1, person1);
    NSLog(@"person2: %p %p %@", person2, &person2, person2);
    NSLog(@"person3: %p %p %@", person3, &person3, person3);

    return 0;
}

运行这段代码,我们可以得到以下输出:

person1: 0x100102e00 0x100102e08 John
person2: 0x100102e80 0x100102e88 Mary
person3: 0x100102f00 0x100102f08 Bob

从输出中可以看出,三个对象的内容是一样的,即JohnMaryBob,这表明它们共享相同的实例变量。三个对象的内存地址也是一样的,即0x100102e000x100102e800x100102f00,这表明它们在内存中占用连续的内存块。唯一不一样的是每个对象的对象指针地址,即0x100102e080x100102e880x100102f08,这表明每个对象都有自己的对象指针。

以上分析结果表明,OC对象在内存中的布局和存储方式与C语言中的结构体非常相似。对象头类似于结构体的首部,实例变量类似于结构体的成员变量。对象指针地址类似于结构体的指针变量,它指向对象在内存中的起始地址。