一 、对象内存的影响因素理解
1.)场景1首先我们创建一个LGPerson继承NSObject对象,里面没有任何属性,成员变量 和方法;
#import
NS_ASSUME_NONNULL_BEGIN
@interface LGPerson : NSObject
@end
NS_ASSUME_NONNULL_END
#import "LGPerson.h"
@implementation LGPerson
@end
int main(int argc, char * argv[]) {
NSString * appDelegateClassName;
@autoreleasepool {
LGPerson *person = [LGPerson alloc];
lg_double2HEX(190.5);
lg_float2HEX(190.5);
appDelegateClassName = NSStringFromClass([AppDelegate class]);
}
return UIApplicationMain(argc, argv, nil, appDelegateClassName);
}
(lldb) po class_getInstanceSize(LGPerson.class)
8
(lldb) po class_getInstanceSize(NSObject.class)
8
(lldb)
场景1打印结果显示:没有添加任何成员属性 LGPerson 与 NSObject的内存长度都为8,两者一样;
2.)场景2,接着往LGPerson里面添加一个属性name,
#import
NS_ASSUME_NONNULL_BEGIN
@interface LGPerson : NSObject
//{
// NSString *name;
//}
@property (nonatomic, copy) NSString *name;
//+ (void)sayNB;
//- (void)sayNB2;
@end
NS_ASSUME_NONNULL_END
#import "LGPerson.h"
@implementation LGPerson
//+ (void)sayNB{
//}
//- (void)sayNB2;
//}
@end
int main(int argc, char * argv[]) {
NSString * appDelegateClassName;
@autoreleasepool {
LGPerson *person = [LGPerson alloc];
lg_double2HEX(190.5);
lg_float2HEX(190.5);
appDelegateClassName = NSStringFromClass([AppDelegate class]);
}
return UIApplicationMain(argc, argv, nil, appDelegateClassName);
}
(lldb) po class_getInstanceSize(LGPerson.class)
16
(lldb) po class_getInstanceSize(NSObject.class)
8
(lldb)
运行结果发现,此时LGPerson添加一个属性name后,内存长度为16,而NSObject 还是8;且在场景2基础添加实例方法和类方法打印的结果一样;在LGPerson将 name新建换成成员变量,打印结果也一样;
3.)场景3:在场景2的基础上,LGPerson多增加一个属性
#import
NS_ASSUME_NONNULL_BEGIN
@interface LGPerson : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString *nickName;
@end
NS_ASSUME_NONNULL_END
(lldb) po class_getInstanceSize(LGPerson.class)
24
(lldb) po class_getInstanceSize(NSObject.class)
8
(lldb)
打印输出结果LGPerson,内存长度变为原来24,而NSObject 内存长度还是8;综合场景1,2,3,继承NSObject的对象,可否认为每增加一个属性,内存长度就加8?继续往下做验证:
A:
@interface LGPerson : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString *nickName;
@property (nonatomic, copy) NSString *hobby;
@end
(lldb) po class_getInstanceSize(LGPerson.class)
32
(lldb)
@interface LGPerson : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString *nickName;
@property (nonatomic, copy) NSString *hobby;
@property (nonatomic, assign) int age;
@end
(lldb) po class_getInstanceSize(LGPerson.class)
40
(lldb)
@interface LGPerson : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString *nickName;
@property (nonatomic, copy) NSString *hobby;
@property (nonatomic, assign) int age;
@property (nonatomic) double height;
@end
(lldb) po class_getInstanceSize(LGPerson.class)
48
(lldb)
@interface LGPerson : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString *nickName;
@property (nonatomic, copy) NSString *hobby;
@property (nonatomic, assign) int age;
@property (nonatomic) double height;
@property (nonatomic) char c1;
@property (nonatomic) char c2;
@end
(lldb) po class_getInstanceSize(LGPerson.class)
48
(lldb)
此时发现,LGPerson ,每增加一个属性,内存长度并不就加8,而是以8字节长度方式进行对齐的:接下来:
int main(int argc, char * argv[]) {
NSString * appDelegateClassName;
@autoreleasepool {
LGPerson *person = [LGPerson alloc];
person.name = @"Cooci";
person.nickName = @"KC";
person.age = 18;
person.height = 190.5;
person.c1 = 'a';
person.c2 = 'b';
lg_double2HEX(18);
lg_float2HEX(190.5);
appDelegateClassName = NSStringFromClass([AppDelegate class]);
}
return UIApplicationMain(argc, argv, nil, appDelegateClassName);
}
进行打印:
(lldb) x/8gx person
0x60000366ed90: 0x00000001010b3860 0x0000001200006261
0x60000366eda0: 0x00000001010ae038 0x00000001010ae058
0x60000366edb0: 0x0000000000000000 0x4067d00000000000
0x60000366edc0: 0x0000000000000000 0x0000000000000000
(lldb) po 0x00000001010ae038
Cooci
(lldb) po 0x00000001010ae058
KC
(lldb) po 0x00000012
18
(lldb) po 0x61
97
(lldb) po 0x62
98
(lldb) e -f f -- 0x4067d00000000000
(long) $7 = 190.5
(lldb)
总结:LGPerson内存的大小受成员变量,属性的影响,不受方法的影响,而且以某种长度方式进行对齐的。
二、结构体内存对齐原则
1.对齐原则
1):数据成员对⻬规则:结构(struct)(或联合(union))的数据成员,第⼀个数据成员放在offset为0的地⽅,以后每个数据成员存储的起始位置要从该成员⼤⼩或者成员的⼦成员⼤⼩(只要该成员有⼦成员,⽐如说是数组,结构体等)的整数倍开始(⽐如int为4字节,则要从4的整数倍地址开始存储。 min(当前开始的位置m n) m = 9 n = 4
9 10 11 12
2):结构体作为成员:如果⼀个结构⾥有某些结构体成员,则结构体成员要从其内部最⼤元素⼤⼩的整数倍地址开始存储.(struct a⾥存有struct b,b⾥有char,int ,double等元素,那b应该从8的整数倍开始存储.)
3):收尾⼯作:结构体的总⼤⼩,也就是sizeof的结果,.必须是其内部最⼤成员的整数倍.不⾜的要补⻬。
各个成员所占字节数对应表:
2.例子1
struct LGStruct1 {
double a; // 8 [0 7]
char b; // 1 [8]
int c; // 4 (9 10 11 [12 13 14 15]
short d; // 2 [16 17] 24
}struct1;
struct LGStruct2 {
double a; // 8 [0 7]
int b; // 4 [8 9 10 11]
char c; // 1 [12]
short d; // 2 (13 [14 15] 16
}struct2;
struct LGStruct3 {
double a; // 8 [0 7]
int b; // 4 [8 9 10 11]
char c; // 1 [12]
short d; // 2 (13 [14 15] 16
int e; // 4 [16 17 18 19] 20 21 22 23 24
struct LGStruct1 str; // 24 (20 21 22 23 [24 25 26 27 ....45 46 47] 48
}struct3;
struct LGStruct4 {
double a; // 8 [0 7]
int b; // 4 [8 9 10 11]
// char c; // 1
// short d; // 2
// int e; // 4
struct LGStruct1 str; // (12 13 14 15 [16 25 26 27 ....33,34] 35 36 37 38 39 40)
}struct4;
int main(int argc, char * argv[]) {
NSString * appDelegateClassName;
@autoreleasepool {
NSLog(@"%lu-%lu-%lu-%lu",sizeof(struct1),sizeof(struct2),sizeof(struct3),sizeof(struct4));
appDelegateClassName = NSStringFromClass([AppDelegate class]);
}
return UIApplicationMain(argc, argv, nil, appDelegateClassName);
}
(lldb)
打印结果
2021-06-09 09:13:39.137431+0800 001-内存对齐原则[82125:2053942] 24-16-48-40
(lldb)
感谢cooci老师的课程指导,以上是学习过程中一些记录,不足之处还请大家指出,好做改进。