揭秘OC对象底层原理(1)——alloc剖析与对象地址对比
2023-09-28 11:31:13
什么是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
从输出中可以看出,三个对象的内容
是一样的,即John
、Mary
和Bob
,这表明它们共享相同的实例变量。三个对象的内存地址
也是一样的,即0x100102e00
、0x100102e80
和0x100102f00
,这表明它们在内存中占用连续的内存块。唯一不一样的是每个对象的对象指针地址
,即0x100102e08
、0x100102e88
和0x100102f08
,这表明每个对象都有自己的对象指针。
以上分析结果表明,OC对象在内存中的布局和存储方式与C语言中的结构体非常相似。对象头类似于结构体的首部,实例变量类似于结构体的成员变量。对象指针地址类似于结构体的指针变量,它指向对象在内存中的起始地址。