美文网首页
02 - 内存对齐解析-结构体嵌套结构体

02 - 内存对齐解析-结构体嵌套结构体

作者: 思路不美 | 来源:发表于2020-09-12 10:19 被阅读0次

一 思考

struct Person{
   int a;
   char b;
   double c;
} person;

struct People{
    char b;
    double c;
    int a;
}people;
int main ()
{
    printf ("%d\n",sizeof(people);  
   printf ("%d\n",sizeof(person);  
    return 0;
}
各类型所占内存大小

真机运行,64位系统上 char + int + double = 1 + 4 + 8 应该占12个字节 ,但运行打印后发现为24 ,16,说明系统存储相应类型有其固定方式即为内存对齐

一 为什么要内存对齐

为了提高程序的性能,数据结构(尤其是栈)应该尽可能地在自然边界上对齐,为了访问未对齐的内存,处理器需要作两次内存访问;然而,对齐的内存访问仅需要一次访问. 例如2-5 4字节数据,在没有内存对齐的情况下要取两次 0-3 4-7 才能得到2-5所需数据.

二 规则 - 如何计算

  • 假设m为当前成员起始存储位置 n为其所需存储大小 需满足 m % n == 0
    否则需从m+1位开始 直到满足条件
  • 当结构体嵌套了结构体时,以数据成员的结构体的自身长度作为外部结构体的最大成员的内存大小,比如结构体a嵌套结构体b,b中有charintdouble等,则b的自身长度为8开始计算b结构体内子成员位置
  • 最后结构体的内存大小必须是结构体中最大成员内存大小的整数倍,不足的需要补齐

解释下上面的24 16 是如何得到的:

Person 结构结构体
计算思路
  • int a 占4个字节从头开始
  • chat b 一个字节 占据 4号位
  • double 8个字节 5, 6 , 7, 无法整除8 故偏移到8号位置 开始到15号 共占8位
  • 结构体总大小位置为16 最大成员为double c8位 可被16整除 故返回16个字节
People 结构结构体
计算思路
  • chat b 从0开始 占一个字节
  • double c8个字节偏移到8号位置向后8位到15
    -int a 4字节可以被16整除 从16开始向后4位到19
  • 最大成员为double c8位, 向后补齐到23 ,共24位可整除8,返回24个字节
三 结构体嵌套结构体
struct Teacher{
    char d;
    int e;
    short f;
    int g;
}teacher;

struct tClass{
    char a;
    int b;
    short c; 
    struct Teacher teacher1;
}class;

int main ()
{
    printf ("%d\n",sizeof(class); //28
    return 0;
}
计算过程
  • chat a , int b , short c 如上面结构体一样计算到位置9
  • Class中最大成员为int 4字节 所以偏移到12号位置存储class中的chat d
  • 剩下的类似普通结构体直到27号位置存储完共28位 28 可以整除最大成员大小 int 4字节 返回28

三 拓展, 应用

  • pragma pack(n) & attribute((aligned (n)))

#pragma pack(1)
struct Person{
  int a;
  char b;
  double c;
} person;// sizeof(person) =  13
#pragma pack()

#define PACKED __attribute__((packed))
struct  PACKED People{
   char b;
   double c;
   int a;
}people;//sizeof(people) =  13
  • #pragma pack(n)为设置采用多少字节对齐
  • #define PACKED __attribute__((packed)) 取消编译过程中的优化对齐

四 OC中的内存优化

  • 由 Person 与People 我们可以得知,在启用内存对齐后,成员相同的结构体,成员顺序不同,则最后实际开辟内存大小也不同,并且所占内存大小大的成员在结构体位置靠前时,最终开辟的空间可能会更小. 不过OC中采用的是16字节对齐,这种方式优化没意义.

OC 属性重排验证

@interface Person : NSObject

@property(nonatomic,assign)NSInteger age;

@property(nonatomic,assign)BOOL sex;

@property(nonatomic,copy)NSString *name;

@property(nonatomic,copy)NSString *address;

@end

-声明一个对象Person 其属性顺序如上

  • 赋值
   Person *person = [[Person alloc] init];
   person.name = @"范热热";
   person.address = @"li bed";
   person.age = 100;
   person.height = 400;
   person.a = 'f';
   person.b = 'b';
  
   NSLog(@"objc对象类型占用的内存大小:%lu",sizeof(person));
   NSLog(@"objc对象实际占用的内存大小:%lu",class_getInstanceSize([Person class]));
   NSLog(@"objc对象分配的内存大小:%lu",malloc_size((__bridge const void*)(person)));
  

查看打印结果 为 8 40 48

  • sizeof(person) 得到的是person指针的大小 占8位 没毛病
  • malloc_size((__bridge const void*)(person)) 实际开辟的大小,采用16字节对齐要被16整除 得48 也可以
  • class_getInstanceSize([Person class]) 这个40是如何得到呢 答案是苹果实际采用的是8字节对齐 验证一下


    person 内存分布
  • 首先我们发现 实际内存中存储的属性值与我们在.h中定义的顺序并不一样
  • 第一个占8位的为ISA指针地址
  • 第二个8位 一共包含了 int age chat a chat b三个属性
  • 第三个8位 为 int height
  • 第四个第五个8位为 NSString 类型

相关文章

  • 结构体

    结构体有名定义 无名定义 结构体嵌套定义 结构体内存对齐 结构体成员初始化 结构体变量引用 结构体的有名定义:直白...

  • 02 - 内存对齐解析-结构体嵌套结构体

    一 思考 真机运行,64位系统上 char + int + double = 1 + 4 + 8 应该占12个字节...

  • 解析C语言结构体对齐(内存对齐问题)

    解析C语言结构体对齐(内存对齐问题) C语言结构体对齐也是老生常谈的话题了。基本上是面试题的必考题。内容虽然很基础...

  • 结构体

    1.结构体 2.结构体的内存对齐模式 编译器在编译一个结构的时候采用内存对齐模式,结构体总是以最大的成员最为对齐单...

  • ndk-基础知识

    数组和指针,数组指针,指针数组 结构体 内存对齐 内存对齐 结构体大小 S5DUD10BN083MHEJEX7TP...

  • 内存对齐详解

    1、什么是内存对齐假设我们声明两个变量: 2、结构体内存对齐规则 结构体所占用的内存与其成员在结构体中的声明顺序有...

  • iOS原理探索02-- 内存对齐

    结构体内存对齐 我们首先定义两个结构体,分别计算他们的内存大小,并讨论内存对齐原理 从两个结构体来看两者没啥大的区...

  • 第一天,内存对齐

    一对齐规则: 1.非结构体类型 32位 4字节对齐,64位 8字节对齐 2.结构体类型 以结构体中,最大内存的整数...

  • 从结构体内存对齐到OC对象内存对齐

    1、结构体内存对齐 结构体对齐规则:1:数据成员对⻬规则:结构(struct)(或联合(union))的数据成员,...

  • 结构体嵌套

    结构体嵌套 结构体嵌套时应逐级引用

网友评论

      本文标题:02 - 内存对齐解析-结构体嵌套结构体

      本文链接:https://www.haomeiwen.com/subject/flocektx.html