内存对齐的原理和使用
1. 什么是内存对齐?
内存对齐是指将数据存储在内存中时,按照数据类型的大小,将数据放在特定的内存边界上。例如,4 字节的 int
通常放在能够被 4 整除的地址上,8 字节的 double
则放在能被 8 整除的地址上。
2. 为什么需要内存对齐?
内存对齐有几个关键的原因:
2.1 提高 CPU 访问速度
- CPU 访问内存时,会一次性读取一定数量的字节(通常是 4、8 或 16 字节)。当数据地址是对齐的,CPU 可以在一次内存读取操作中完整读取数据,这显著提升了效率。
- 如果数据没有对齐,CPU 可能需要执行多次内存读取操作来获取完整的数据。例如,如果一个 4 字节的
int
存储在一个未对齐的位置(比如 3 字节边界上),那么 CPU 需要读取两次内存块,将其拼接成一个完整的数据。这会降低系统性能。
2.2 硬件要求
- 一些处理器架构(如早期的 RISC 处理器或某些嵌入式系统)不允许从非对齐的内存地址读取数据。如果数据没有对齐,硬件可能会抛出错误,导致程序崩溃。
- 对于允许非对齐访问的架构(如大多数 x86 处理器),虽然可以处理非对齐数据,但这往往伴随着性能上的显著开销。
2.3 避免额外的计算复杂性
- 如果数据不对齐,编译器和硬件需要额外计算如何正确读取和写入数据。这增加了编译器和 CPU 的复杂性,也可能会导致更高的功耗。
3. 内存对齐的原理
内存对齐遵循以下基本规则:
- 数据的起始地址必须是它大小的整数倍。例如,4 字节的
int
变量的地址通常是 4 的倍数,8 字节的double
变量的地址是 8 的倍数。 - 现代编译器通常会为不同类型的数据设置默认的对齐规则,确保数据存储在合适的内存地址上。
4. 内存对齐的代价:填充字节
为了满足对齐要求,编译器可能会在内存中引入一些填充字节(padding bytes),这些字节不会存储有效数据,但它们确保后续的数据地址是对齐的。
示例:
假设有一个包含不同类型成员的结构体:
struct Example {char a; // 1字节int b; // 4字节short c; // 2字节
};
在 32 位系统上,内存对齐可能是这样的:
| a (1 byte) | padding (3 bytes) | b (4 bytes) | c (2 bytes) | padding (2 bytes) |
a
占 1 字节,但b
是 4 字节的int
,需要对齐到 4 字节边界,因此a
后面有 3 个填充字节。c
是 2 字节的short
,为了对齐结构体的总大小,也可能引入额外的 2 字节填充。
总大小为 12 字节,而不是简单的 7 字节。
5. 内存对齐的影响
- 性能提升:对齐使得 CPU 能够更高效地访问内存,尤其是当大量数据处理时,这一点显得尤为重要。
- 空间开销:虽然内存对齐可能引入填充字节,增加内存使用,但这通常是必要的权衡,因为提升了数据访问效率。
6. 手动控制对齐
在 C++ 中,可以使用 #pragma pack
或 alignas
关键字来手动调整结构体的对齐方式。例如,#pragma pack(1)
可以让编译器不插入填充字节,减少内存占用。但这可能会牺牲性能,甚至导致某些平台上的错误。
7.使用#pragma pack
来关闭内存对齐
手动控制内存对齐手动控制内存对齐是一种手段,可以通过编译器指令调整数据结构的内存对齐方式,以减少内存浪费或满足特殊的内存布局需求。通常情况下,编译器会自动为数据类型安排合理的对齐,但在某些场景下,你可能需要手动修改对齐策略。常用的手段包括 #pragma pack
和 alignas
关键字。下面详细解释这两种方法:
1. #pragma pack
#pragma pack
是一种预处理指令,用来控制结构体或类的对齐方式。它可以通过设定字节边界来调整结构体中的填充字节。
语法:
#pragma pack(n)
- 其中
n
表示对齐字节边界,例如1
、2
、4
、8
等。编译器会强制将结构体成员对齐到n
字节的边界上。
示例:
#pragma pack(1)
struct Example {char a; // 1字节int b; // 4字节short c; // 2字节
};
#pragma pack() // 恢复默认对齐
在 #pragma pack(1)
下,编译器将强制所有成员不插入任何填充字节,对齐到 1 字节边界,结构体内存布局如下:
| a (1 byte) | b (4 bytes) | c (2 bytes) |
此时,整个结构体大小为 7 字节,没有任何填充字节。
不使用 #pragma pack
的默认布局:
如果不使用 #pragma pack(1)
,编译器会按照默认对齐方式处理。以 4
字节对齐为例,Example
结构体的默认内存布局为:
| a (1 byte) | padding (3 bytes) | b (4 bytes) | c (2 bytes) | padding (2 bytes) |
默认情况下,int b
需要对齐到 4 字节边界,因此在 a
后面插入了 3 个字节的填充,使得 b
正好对齐到 4 字节边界,最后结构体大小为 12 字节。
优缺点:
- 优点:可以减少不必要的内存填充,尤其在数据存储、网络传输等场景下,可以节省内存。
- 缺点:强制对齐到小字节边界可能导致性能下降,尤其是在现代 CPU 上,非对齐的内存访问可能会引起多次内存访问,导致系统性能变差。
8 使用alignas
关键字
alignas
是 C++11 引入的关键字,它可以在声明变量或结构体成员时,指定某个成员的对齐方式。
语法:
alignas(n) type var;
- 其中
n
是对齐要求的字节数,type
是变量类型,var
是变量名称。alignas
可以为数据结构的某个特定成员或整个结构体设置对齐。
示例:
struct Example {char a; // 1字节alignas(8) int b; // 强制 b 对齐到 8 字节short c; // 2字节
};
在这个例子中,int b
强制对齐到 8 字节边界。内存布局将变为:
| a (1 byte) | padding (7 bytes) | b (4 bytes) | c (2 bytes) | padding (2 bytes) |
整个结构体大小为 16 字节。相比默认情况下的对齐方式(4 字节对齐),b
现在被强制对齐到 8 字节,因此插入了更多的填充字节以确保对齐。
对齐整个结构体:
alignas
还可以用于整个结构体的对齐,例如:
struct alignas(16) Example {char a;int b;
};
这会确保 Example
结构体的起始地址是 16 字节对齐的,通常在需要满足特定硬件需求或 SIMD(单指令多数据)操作时会使用。
优缺点:
- 优点:
alignas
提供了更细粒度的控制,允许为特定变量或结构体自定义对齐方式。 - 缺点:过度使用可能增加填充字节,从而浪费内存;同时,也会影响性能,尤其是在对齐过度的情况下。
3. #pragma pack
和 alignas
的比较
- 适用范围:
#pragma pack
主要用于控制整个结构体的对齐方式,而alignas
可以细粒度控制特定成员或整个结构体的对齐。 - 灵活性:
alignas
更灵活,因为它可以精确控制特定成员的对齐,而#pragma pack
是全局性的。 - 兼容性:
#pragma pack
是一种编译器指令,不同编译器可能有不同的实现和支持;alignas
是标准的 C++ 关键字,跨平台兼容性更好。
相关文章:
内存对齐的原理和使用
1. 什么是内存对齐? 内存对齐是指将数据存储在内存中时,按照数据类型的大小,将数据放在特定的内存边界上。例如,4 字节的 int 通常放在能够被 4 整除的地址上,8 字节的 double 则放在能被 8 整除的地址上。 2. 为什么…...

搭建企业级私有仓库harbor
华子目录 harbor简介实验环境准备下载软件包安装docker-cehosts解析 实验步骤配置https加密传输解压进入解压目录,修改文件配置启动harbor 测试客户端配置harbor本地加速器注意 通过docker compose管理harbor harbor简介 harbor是由wmware公司开源的企业级docker r…...
互联网前后端分离的开发场景,一般会员和数据权限的判断是放在前端还是后端?
推荐学习文档 golang应用级os框架,欢迎stargolang应用级os框架使用案例,欢迎star案例:基于golang开发的一款超有个性的旅游计划app经历golang实战大纲golang优秀开发常用开源库汇总想学习更多golang知识,这里有免费的golang学习笔…...

李宏毅机器学习2022-HW8-Anomaly Detection
文章目录 TaskBaselineReportQuestion2 Code Link Task 异常检测Anomaly Detection 将data经过Encoder,在经过Decoder,根据输入和输出的差距来判断异常图像。training data是100000张人脸照片,testing data有大约10000张跟training data相同…...

用户体验分享 | YashanDB V23.2.3安装部署
近期崖山新版体验过程中,总能看到用户提问:openssl版本问题、monit命令找不到问题、yashan用户权限问题、数据库重装问题 今日整理了多位用户的安装经验,希望能够帮助到大家~ 1.Lucifer三思而后行 :YashanDB 个人版数据库安装部…...
【漏洞复现】泛微OA E-Office /E-mobile/App/init.php 任意文件上传漏洞
免责声明: 本文旨在提供有关特定漏洞的信息,以帮助用户了解潜在风险。发布此信息旨在促进网络安全意识和技术进步,并非出于恶意。读者应理解,利用本文提到的漏洞或进行相关测试可能违反法律或服务协议。未经授权访问系统、网络或应用程序可能导致法律责任或严重后果…...

SpringCloudEureka实战:搭建EurekaServer
1、依赖引入 <dependencies><!-- 注册中心 --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-server</artifactId></dependency> </dependencies> <de…...

DataLight(V1.4.5) 版本更新,新增 Ranger、Solr
DataLight(V1.4.5) 版本更新,新增 Ranger、Solr DataLight 迎来了重大的版本更新,现已发布 V1.4.5 版本。本次更新对平台进行了较多的功能拓展和优化,新增了对 Ranger 和 Solr 服务组件的支持,同时对多项已…...

深度解析:Python蓝桥杯青少组精英赛道与高端题型概览
目录 一、蓝桥杯青少组简介二、赛项组别与年龄范围三、比赛内容与题型1. 基础知识范围2. 题型设置2.1 选择题2.2 编程题 3. 考试时长 四、奖项设置与激励措施五、总结 一、蓝桥杯青少组简介 蓝桥杯全国软件和信息技术专业人才大赛(简称“蓝桥杯”)是由工…...

如何使用SCCMSecrets识别SCCM策略中潜在的安全问题
关于SCCMSecrets SCCMSecrets是一款针对SCCM策略的安全扫描与检测工具,该工具旨在提供一种有关 SCCM 策略的全面安全检测方法。 该工具可以从各种权限级别执行,并将尝试发现与策略分发相关的潜在错误配置。除了分发点上托管的包脚本外,它还将…...
Qt 信号重载问题--使用lambda表达式--解决方法
在connect()中,使用lambda表达式时遇到信号重载,无法识别使用哪个参数时,可通过以下方法处理: 1. 使用QOverload: Qt5.7才有 connect(comboBox,QOverload<int>::of(&QComboBox::currentIndexChanged), [](int index)…...
并行编程实战——TBB框架的应用之一Supra的基础
一、TBB的应用 在前面分析了TBB框架的各种基本知识和相关的基础应用。这些基础的应用很容易通过学习文档或相关的代码来较为轻松的掌握。为了能够更好的理解TBB框架的优势,这里从一个开源的应用程序来分析一下TBB在其中的更高一层的抽象应用,以方便开发…...
std::vector
std::vector是C标准库中一个非常强大的容器类,它提供了动态数组的功能。std::vector可以自动调整大小,提供了随机访问的能力,同时还支持在序列的尾部高效地添加和删除元素。 当创建一个空的std::vector对象时,它不分配任何内存&a…...
Java Web 之 Cookie 详解
在 JavaWeb 开发中,Cookie 就像网站给浏览器贴的小纸条,用于记录一些用户信息或状态,方便下次访问时识别用户身份或进行个性化服务。 也可以这么理解: 场景一:想象一下,你去一家咖啡店,店员认…...
linux系统下让.py文件开机自启动
一 创建服务文件 1、打开终端 2、切换到root用户 sudo su3、创建一个新的systemd服务文件 nano /etc/systemd/system/total_test0619.service 4、在服务文件中添加以下内容 [Unit] DescriptionRun total_test0619.py at startup[Service] Typesimple ExecStart/usr/bin/n…...
linux远程桌面:xrdp 安装失败
window 如何远程 Linux 桌面 安装xrdp yum install xrdpsystemctl start xrdp 如果找不到软件包,就安装epel源,最好改成国内镜像的 在 /etc/yum.repos.d/ 下创建epel.repo,内容如下 [epel] nameExtra Packages for Enterprise Linux 7 - $basearch …...
9.30Python基础-元组(补充)、字典、集合
Python元组(tuple)补充 1、元组的不可变性 元组(tuple)是Python中的一种内置数据类型,用于存储不可变的序列。虽然元组本身不可变,但元组内的元素如果是可变对象(如列表)ÿ…...

桥接模式和NET模式的区别
桥接模式和NET模式的区别 NAT模式: NAT:网络地址转换(模式):借助宿主机来上网,没桥接那么麻烦,只用配置DNS即可。 缺点:扎根于宿主机,不能和局域网内其它真实的主机进行…...
Pigar:Python 项目的依赖管理利器
🌟 引言 在Python项目开发过程中,依赖管理是一个不可忽视的环节。一个精确且易于维护的requirements.txt文件对于项目的部署和协作至关重要。今天,我们将介绍一款名为Pigar的自动生成requirements.txt文件的依赖管理工具,它通过一…...

泰勒图 ——基于相关性与标准差的多模型评价指标可视化比较-XGBoost、sklearn
1、基于相关性与标准差的多模型评价指标可视化比较 # 数据读取并分割 import pandas as pd import numpy as np import matplotlib.pyplot as plt from sklearn.model_selection import train_test_split plt.rcParams[font.family] = Times New Roman plt.rcParams[axes.unic…...

Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误
HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误,它们的含义、原因和解决方法都有显著区别。以下是详细对比: 1. HTTP 406 (Not Acceptable) 含义: 客户端请求的内容类型与服务器支持的内容类型不匹…...
应用升级/灾备测试时使用guarantee 闪回点迅速回退
1.场景 应用要升级,当升级失败时,数据库回退到升级前. 要测试系统,测试完成后,数据库要回退到测试前。 相对于RMAN恢复需要很长时间, 数据库闪回只需要几分钟。 2.技术实现 数据库设置 2个db_recovery参数 创建guarantee闪回点,不需要开启数据库闪回。…...

Docker 运行 Kafka 带 SASL 认证教程
Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明:server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...

最新SpringBoot+SpringCloud+Nacos微服务框架分享
文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的,根据Excel列的需求预估的工时直接打骨折,不要问我为什么,主要…...
vue3 字体颜色设置的多种方式
在Vue 3中设置字体颜色可以通过多种方式实现,这取决于你是想在组件内部直接设置,还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法: 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...
【android bluetooth 框架分析 04】【bt-framework 层详解 1】【BluetoothProperties介绍】
1. BluetoothProperties介绍 libsysprop/srcs/android/sysprop/BluetoothProperties.sysprop BluetoothProperties.sysprop 是 Android AOSP 中的一种 系统属性定义文件(System Property Definition File),用于声明和管理 Bluetooth 模块相…...
Java 加密常用的各种算法及其选择
在数字化时代,数据安全至关重要,Java 作为广泛应用的编程语言,提供了丰富的加密算法来保障数据的保密性、完整性和真实性。了解这些常用加密算法及其适用场景,有助于开发者在不同的业务需求中做出正确的选择。 一、对称加密算法…...
vue3 定时器-定义全局方法 vue+ts
1.创建ts文件 路径:src/utils/timer.ts 完整代码: import { onUnmounted } from vuetype TimerCallback (...args: any[]) > voidexport function useGlobalTimer() {const timers: Map<number, NodeJS.Timeout> new Map()// 创建定时器con…...
uniapp中使用aixos 报错
问题: 在uniapp中使用aixos,运行后报如下错误: AxiosError: There is no suitable adapter to dispatch the request since : - adapter xhr is not supported by the environment - adapter http is not available in the build 解决方案&…...

图表类系列各种样式PPT模版分享
图标图表系列PPT模版,柱状图PPT模版,线状图PPT模版,折线图PPT模版,饼状图PPT模版,雷达图PPT模版,树状图PPT模版 图表类系列各种样式PPT模版分享:图表系列PPT模板https://pan.quark.cn/s/20d40aa…...