【C++】内存对齐原理及详解(附带相关案例)

简介: 【C++】内存对齐原理及详解(附带相关案例)

内存对齐无论是在校招笔试中、还是秋招面试中都是重点,下面对内存对齐进行详细介绍!!!


一、内存对齐应用的数据类型


       内存对齐应用于三种数据类型中:struct、class、union;


二、内存对齐原则


1、数据成员对齐规则


 结构(struct)或联合(union)的数据成员,第一个数据成员放在offset0的地,以后每个数据成员存储的起始位置要从该成员大小或者成员的子成员大小的整数倍开始。


2、结构体作为成员


 如果一个结构里有某些结构体成员,则结构体成员要从其内部"最宽基本类型成员"的整数倍地址开始存储。(struct a里存有struct b,b里有char,int ,double等元素,b应该从8的整数倍开始存储)


3、收尾工作


    结构体的总大小,也就是sizeof的结果,必须是其内部最大成员的"最宽基本类型成员"的整数倍。不足的要补齐。(基本类型不包括struct/class/uinon)


4、sizeof(union)


 以结构里面size最大元素为unionsize,因为在某一时刻,union只有一个成员真正存储于该地址。


三、什么是内存对齐


 那么什么是字节对齐?在C语言中,结构体是一种复合数据类型,其构成元素既可以是基本数据类型(如int、long、flfloat等)的变量,也可以是一些复合数据类型(如数组、结构体、联合体等) 的数据单元。在结构体中,编译器为结构体的每个成员按其自然边界(alignment)分配空间。 各个成员按照它们被声明的顺序在内存中顺序存储,第一个成员的地址和整个结构体的地址相同。 为了使CPU能够对变量进行快速的访问,变量的起始地址应该具有某些特性,即所谓的“对齐”,比 如4字节的int型,其起始地址应该位于4字节的边界上,即起始地址能够被4整除,也即“对齐”跟数据在内存中的位置有关。如果一个变量的内存地址正好位于它长度的整数倍,他就被称做自然对齐。


       比如在32位cpu下,假设一个整型变量的地址为0x00000004(为4的倍数),那它就是自然对齐的, 而如果其地址为0x00000002(非4的倍数)则是非对齐的。现代计算机中内存空间都是按照byte 划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定 类型变量的时候经常在特定的内存地址访问,这就需要各种类型数据按照一定的规则在空间上排 列,而不是顺序的一个接一个的排放,这就是对齐。


四、为什么要字节对齐


  需要字节对齐的根本原因在于CPU访问数据的效率问题。假设上面整型变量的地址不是自然对齐, 比如为0x00000002,则CPU如果取它的值的话需要访问两次内存,第一次取从0x00000002- 0x00000003的一个short,第二次取从0x00000004-0x00000005的一个short然后组合得到所要的数据,如果变量在0x00000003地址上的话则要访问三次内存,第一次为char,第二次为 short,第三次为char,然后组合得到整型数据。


       而如果变量在自然对齐位置上,则只要一次就可以取出数据。一些系统对对齐要求非常严格,比如sparc系统,如果取未对齐的数据会发生错误,而在x86上就不会出现错误,只是效率下降。 各个硬件平台对存储空间的处理上有很大的不同。一些平台对某些特定类型的数据只能从某些特定 地址开始存取。比如有些平台每次读都是从偶地址开始,如果一个int型(假设为32位系统)如果 存放在偶地址开始的地方,那么一个读周期就可以读出这32bit,而如果存放在奇地址开始的地 方,就需要2个读周期,并对两次读出的结果的高低字节进行拼凑才能得到该32bit数据。显然在读 取效率上下降很多。


五、字节对齐实例


1、union字节对齐


union example { 
    int a[5]; 
    char b; 
    double c; 
};
int result = sizeof(example);

说明:如果以最长20字节为准,内部double占8字节,这段内存的地址0x00000020并不是double的整数 倍,只有当最小为0x00000024时可以满足整除double(8Byte)同时又可以容纳int a[5]的大小, 所以正确的结果应该是result=24;


2、struct字节对齐


struct example { 
    int a[5]; 
    char b; 
    double c; 
}test_struct; 
int result = sizeof(test_struct);

说明:如果我们不考虑字节对齐,那么内存地址0x0021不是double(8Byte)的整数倍,所以需要字节对 齐,那么此时满足是double(8Byte)的整数倍的最小整数是0x0024,说明此时char b对齐int扩充 了三个字节。所以最后的结果是result=32;

struct example { 
    char b; 
    double c; 
    int a; 
}test_struct; 
int result = sizeof(test_struct);

说明:字节对齐除了内存起始地址要是数据类型的整数倍以外,还要满足一个条件,那就是占用的内存空间大 小需要是结构体中占用最大内存空间的类型的整数倍,所以20不是double(8Byte)的整数倍,我们还 要扩充四个字节,最后的结果是result=24;

相关文章
|
5天前
|
算法 调度 UED
深入理解操作系统内存管理:原理与实践
【4月更文挑战第23天】 在现代计算机系统中,操作系统的内存管理是保证系统高效、稳定运行的关键组成部分。本文旨在深入探讨操作系统中内存管理的理论基础、关键技术以及实际操作过程,通过对内存分配策略、虚拟内存技术、分页与分段机制等核心概念的详细解析,为读者提供一个清晰、全面的内存管理视角。此外,文章还将通过案例分析,展示内存管理在解决实际问题中的应用,以期加深读者对操作系统内存管理复杂性的认识和理解。
|
20天前
|
存储 C++ 容器
C++STL(标准模板库)处理学习应用案例
【4月更文挑战第8天】使用C++ STL,通过`std:vector`存储整数数组 `{5, 3, 1, 4, 2}`,然后利用`std::sort`进行排序,输出排序后序列:`std:vector<int> numbers; numbers = {5, 3, 1, 4, 2}; std:sort(numbers.begin(), numbers.end()); for (int number : numbers) { std::cout << number << " "; }`
19 2
|
30天前
|
缓存 Java C#
【JVM故障问题排查心得】「Java技术体系方向」Java虚拟机内存优化之虚拟机参数调优原理介绍(一)
【JVM故障问题排查心得】「Java技术体系方向」Java虚拟机内存优化之虚拟机参数调优原理介绍
82 0
|
5天前
|
存储 人工智能 程序员
【重学C++】【内存】关于C++内存分区,你可能忽视的那些细节
【重学C++】【内存】关于C++内存分区,你可能忽视的那些细节
35 1
|
5天前
|
设计模式 C语言 C++
【C++进阶(六)】STL大法--栈和队列深度剖析&优先级队列&适配器原理
【C++进阶(六)】STL大法--栈和队列深度剖析&优先级队列&适配器原理
|
5天前
|
存储 C++
C++底层原理
C++底层原理
13 0
|
20天前
|
存储 算法
深入理解操作系统内存管理:原理与实践
【4月更文挑战第8天】 在现代计算机系统中,操作系统扮演着关键角色,特别是在内存资源的管理上。本文将深入探讨操作系统中的内存管理机制,包括虚拟内存、物理内存的分配与回收,以及页面置换算法等关键技术。通过分析不同内存管理策略的优势与局限性,本文旨在为读者提供一套系统的内存管理知识框架,帮助理解操作系统如何高效、安全地管理有限的内存资源以满足多任务处理的需求。
|
20天前
|
程序员 C++
C++语言模板学习应用案例
C++模板实现通用代码,以适应多种数据类型。示例展示了一个计算两数之和的模板函数`add&lt;T&gt;`,可处理整数和浮点数。在`main`函数中,展示了对`add`模板的调用,分别计算整数和浮点数的和,输出结果。
12 2
|
26天前
|
存储 算法 安全
深入理解操作系统内存管理:原理与实践
【4月更文挑战第2天】 在现代计算机系统中,操作系统的内存管理是核心功能之一,它负责协调和分配系统内存资源。本文将探讨操作系统内存管理的基本原理,包括内存的分配与回收、分页机制、虚拟内存的使用以及内存保护。通过对这些概念的细致剖析,我们不仅能够理解操作系统如何高效利用有限的物理内存,还能够认识到内存管理对系统稳定性和性能的重要性。文章还将简要讨论现代操作系统中内存管理的创新趋势及其对未来计算技术的潜在影响。
15 2
|
1月前
|
存储 Linux C语言
【C++练级之路】【Lv.5】动态内存管理(都2023年了,不会有人还不知道new吧?)
【C++练级之路】【Lv.5】动态内存管理(都2023年了,不会有人还不知道new吧?)