影响OC对象内存大小的因素
数据类型内存大小:
代码分析
@interface QHPerson : NSObject
{
//isa 8
NSString *level; //8
}
@property (nonatomic, copy) NSString *name; //8
@property (nonatomic, copy) NSString *nickName; //8
@property (nonatomic, assign) int age; //4
@property (nonatomic, assign) long height; //8
@end
QHPerson *p = [[QHPerson alloc] init];
p.name = @"qinhan";
p.age = 18;
size_t instansSize = class_getInstanceSize([QHPerson class]);
NSLog(@"instansSize :%lu",instansSize);
通过class_getInstanceSize
获取实例的大小,
根据我上面标注的结果是44,为什么打印结果是48内,实际上在alloc的时候苹果做了8字节的对齐处理,参考上篇文章
控制变量,我们添加个方法
发现内存大小不变
减少成员变量或属性
打印结果:
发现内存大小变小
总结:
对象分配的内存大小
和成员变量
和属性
有关
OC对象内存分析
然后我们去掉
char1
这个变量- 可以看到第三段内存的变化
0x0000001200000063
,第二次0x0000000000000012
,两次int所占的字节不一样,由此可见底层做了字节对齐的优化处理。 -
x/8gx p
是lldb简写指令,下面附上一张别人总结的,以便理解
pragma pack(show)
- pragma pack(show) 的大致作用就是改变编译器的对齐方式,如果不设置默认是8,我们也可以通过show的置来改变。
- 最终的对齐方式还是要取变量所占的字节对比,取更小的,
min(a,show)
. 比如int是4字节,默认是8 ,该成员就会以4字节对齐。
内存对齐原则
数据成员对齐规则:结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员存储的起始位置要从该成员大小或者成员的子成员大小(只要该成员有子成员,比如说是数组,结构体等)的整数倍开始(比如int在32位机为4字节,则要从4的整数倍地址开始存储。这个整数应该是编译器设置的值和成员类型的值中的小值。
2.当结构体嵌套
了结构体时,作为数据成员的结构体的自身长度取内部结构体的最大成员的内存大小,比如结构体a
嵌套结构体b
,b
中有char
、int
、double
等,去最大的作为b
的自身长度为,这里取double
类型为8,这个8也要于编译器设置的值进行对比,如果show = 4
,那么应该去4.
3.结构体
的内存大小必须是结构体
中最大成员
内存大小的整数倍,不足的需要补齐
规则验证
下面定义了两个结构体来验证一下内存的大小
struct QHStruct1{
char a; //1字节
double b; //8字节
int c; //4字节
short d; //2字节
}QHStruct1;
struct QHStruct2{
double b; //8字节
int c; //4字节
short d; //2字节
char a; //1字节
}QHStruct2;
查看打印结果
纳尼,打印结果不一样,同样的成员顺序不一样打印结果居然不一样。但是如果我们了解
内存对齐规则
,就不会这么认为了通过上面的对齐规则,通过图表的形式展现了,
QHStruct1
和```QHStruct2``的内存分布,与打印结果一致计算结构体QHStruct1
内存大小详细流程
变量a
:占1
个字节,从0
开始,此时min(0,1
),即 0
存储 a
变量b
:占8
个字节,从1
开始,此时min(1,8)
,1
不能整除8
,继续往后移动,知道min(8,8)
,从8
开始,即8-15
存储b
变量c
:占4
个字节,从16
开始,此时min(16,4)
,16
可以整除4
,即 16-19
存储 c
变量d
:占2
个字节,从20
开始,此时min(20, 2)
,20
可以整除2
,即20-21
存储 d
计算结构体QHStruct2
内存大小详细流程
变量b
:占8
个字节,从0
开始,此时min(0,8
),即0-7
存储b
变量c
:占4
个字节,从8
开始,此时min(8,4)
,8
可以整除4
,即 8-11
存储c
变量d
:占2
个字节,从12
开始,此时min(12, 2)
,12可以整除2
,即12-13
存储 d
变量a
:占1
个字节,从14
开始,此时min(14,1)
,即 14
存储a
结构体嵌套
struct QHStruct2{
double b; //8字节
int c; //4字节
short d; //2字节
char a; //1字节
}QHStruct2;
struct QHstruct3{
double b; //8字节 0-7
int c; //4字节 8 9 10 11
short d; //2字节 12 13
char a; //1字节 14
struct QHStruct2 str; //
}QHstruct3;
其实嵌套后和没有嵌套逻辑一样,只不过这里的str
要按照成员里面最大的字节8
来计算,相当于n =8
, 这样就很容易算出,结构体从16
出开始放,这样就是16+16=32
字节
计算内存大小的几个方法
class_getInstanceSize
sizeof
malloc_size
举个例子
- (void)test1
{
QHPerson *p = [[QHPerson alloc] init];
p.name = @"qinhan";
p.age = 18;
p.nickName = @"123";
//p.height = 180;
p->level = @"青铜";
// p.char1 = 'c';
size_t instansSize = class_getInstanceSize([QHPerson class]);
NSLog(@"sizeOf :%lu",sizeof(p));
NSLog(@"instansSize :%lu",instansSize);
NSLog(@"objc对象实际分配的内存大小:%lu",malloc_size((__bridge const void*)(p)));
}
打印结果
发现instansSize
计算的大小和malloc_size
计算大小不一样,
这是因为instansSize
是8
字节对齐,也就是是8
的倍数
imalloc_size
是16
字节对齐,也就是16
的倍数
内存优化
通过上面结构体内存对齐以及上面的内存分析,发现属性的顺序不一样,内存大小不一样,所以苹果底层做了一些优化.用空间换时间,将类中的属性进行重排,以此来达到内存优化的目的