注:以下都是基于64位系统来阐述的
NSObject对象占用的内存
NSObject *object = [[NSObject alloc] init];
int min = class_getInstanceSize([object class]);//计算至少需要多少内存
int size = malloc_size((__bridge const void *)object);//实际分配多少内存
结果:
2021-12-20 15:27:25.809499+0800 objecttest[509:61437] object min:8 size:16
由于NSObject底层实现只存储了isa指针,在64位系统中,指针占8个字节,应此至少需要8字节内存空间,由于要考虑到内存对齐,64位系统的内存对齐位数默认为16字节,因此实际上分配了16字节的内存空间。
实际对象举例
@interface Person : NSObject
@property(nonatomic, assign) int age;
@end
@interface Student : Person
@property(nonatomic, assign)int weigth;
@property(nonatomic, assign)int height;
@end
Student *student = [[Student alloc] init];
min = class_getInstanceSize([student class]);//计算至少需要多少内存
size = malloc_size((__bridge const void *)student);//实际分配多少内存
NSLog(@"min:%d size:%d", min, size);
结果为:
2021-12-20 15:27:25.809608+0800 objecttest[509:61437] min:24 size:32
student对象中存储了isa指针,3个int变量,一共占用8+3*4 = 20个自己,由于要结构体对齐,需要为8的倍数,因此至少需要24个字节内存空间,但又要内存对齐,因此实际分配的存储空间为32字节
NSString的认识
NSString的结构较复杂,系统根据不同的情况,生成不同的对象。有如下三种类型:
- __NSCFConstantString:常量字符串,编译时常量,对象存储在字符串常量区
- NSTaggedPointerString:标签字符串,苹果在 64 位环境下对 NSString,NSNumber 等对象做的一些优化,简单来讲可以理解为把指针指向的内容直接放在了指针变量的内存地址中,也是常量对象,在运行时创建
对于 NSString 对象来讲,当非字面值常量的数字,英文字母字符串的长度能够被 NSTaggedPointerString 类型容纳时,就是NSTaggedPointerString类型,否则就是__NSCFString类型。如果有中文或其他特殊符号(可能是非 ASCII 字符)存在的话则会直接成为 )__NSCFString 类型 - __NSCFString:对象在被创建时获得了 1 的引用计数,存储在堆上,运行时创建
NSString *str1 = @"abc";
NSString *str2 = [NSString stringWithFormat:@"123"];
NSString *str3 = [NSString stringWithString:@"def"];
NSString *str4 = [[NSString alloc] initWithFormat:@"456"];
NSString *str5 = [[NSString alloc] initWithString:@"ghi"];
NSString *str6 = [[NSString alloc] initWithFormat:@"阿"];
NSString *str7 = [[NSString alloc] initWithFormat:@"aaaaaaaaaaaa"];
NSLog(@"str1 class:%@ p:%p retainCount:%zd", [str1 class], str1, CFGetRetainCount((__bridge CFTypeRef)(str1)));
NSLog(@"str2 class:%@ p:%p retainCount:%zd", [str2 class], str2, CFGetRetainCount((__bridge CFTypeRef)(str2)));
NSLog(@"str3 class:%@ p:%p retainCount:%zd", [str3 class], str3, CFGetRetainCount((__bridge CFTypeRef)(str3)));
NSLog(@"str4 class:%@ p:%p retainCount:%zd", [str4 class], str4, CFGetRetainCount((__bridge CFTypeRef)(str4)));
NSLog(@"str5 class:%@ p:%p retainCount:%zd", [str5 class], str5, CFGetRetainCount((__bridge CFTypeRef)(str5)));
NSLog(@"str6 class:%@ p:%p retainCount:%zd", [str6 class], str6, CFGetRetainCount((__bridge CFTypeRef)(str6)));
NSLog(@"str7 class:%@ p:%p retainCount:%zd", [str7 class], str7, CFGetRetainCount((__bridge CFTypeRef)(str7)));
结果:
2021-12-20 15:27:25.809766+0800 objecttest[509:61437] str1 class:__NSCFConstantString p:0x102e38138 retainCount:1152921504606846975
2021-12-20 15:27:25.809855+0800 objecttest[509:61437] str2 class:NSTaggedPointerString p:0xa565ff4fab6b39b9 retainCount:9223372036854775807
2021-12-20 15:27:25.809895+0800 objecttest[509:61437] str3 class:__NSCFConstantString p:0x102e38178 retainCount:1152921504606846975
2021-12-20 15:27:25.810144+0800 objecttest[509:61437] str4 class:NSTaggedPointerString p:0xa565ff4fab3b49e9 retainCount:9223372036854775807
2021-12-20 15:27:25.810380+0800 objecttest[509:61437] str5 class:__NSCFConstantString p:0x102e381b8 retainCount:1152921504606846975
2021-12-20 15:27:25.810511+0800 objecttest[509:61437] str6 class:__NSCFString p:0x281080220 retainCount:1
2021-12-20 15:27:25.810644+0800 objecttest[509:61437] str7 class:__NSCFString p:0x281080240 retainCount:1
str1,str3,str5都是__NSCFConstantString。str2,str4属于class:NSTaggedPointerString。str6,str7为__NSCFString。从引用技术看:属于常量的__NSCFConstantString,class:NSTaggedPointerString引用计数都很大,不能被释放。__NSCFString的引用计数为1。str2与str7都是基本字符串,但str7的长度超过了NSTaggedPointerString的存储空间,因此使用__NSCFString类型。str6使用了中文,则直接使用__NSCFString类型。
block
block是封装了函数调用及函数调用环境的OC对象。
block有三种类型,都是继承NSBlock。
- NSGlobalBlock ( _NSConcreteGlobalBlock )数据区域
- NSStackBlock ( _NSConcreteStackBlock )栈区
- NSMallocBlock ( _NSConcreteMallocBlock )堆区
block调用copy的表现: