内存管理解析(2) 字节对齐详解

2023-10-29

很想贴出转载链接, 找不到原来看的资料了, 只有从个人记录的笔记上挪过来, 如有错误请留言指正

目录

一. 什么是字节对齐

二. 为什么要字节对齐

 

三. 有哪些对齐形式

1. 结构体对齐

对齐值:

对齐准则:

对齐的隐患:

更改对齐方式

2. 栈内存对齐

3. 位域对齐

位域说明

使用场景

对齐规则

注意事项

四. linux内存分配对齐


一. 什么是字节对齐

内存空间按照字节划分,理论上可以从任何起始地址访问任意类型的变量。

但实际中在访问特定类型变量时经常在特定的内存地址访问,这就需要各种类型数据按照一定的规则在空间上排列,而不是顺序一个接一个地存放,这就是对齐。

二. 为什么要字节对齐

平台原因(移植原因):不同硬件平台对存储空间的处理上存在很大的不同。某些平台对特定类型的数据只能从特定地址开始存取,而不允许其在内存中任意存放。

性能原因: 数据结构(尤其是栈),应该尽可能在自然边界上对齐,因为在访问为对齐的内存时,处理器需要访问两次,而对齐的内存处理器只需要访问一次。

借个图做说明: 32位的Intel处理器通过总线访问(包括读和写)内存数据。每个总线周期从偶地址开始访问32位内存数据,内存数据以字节为单位存放。如果一个32位的数据没有存放在4字节整除的内存地址处,那么处理器就需要2个总线周期对其进行访问,显然访问效率下降很多。

 

三. 有哪些对齐形式

1. 结构体对齐

对齐值:

     1) 数据类型自身的对齐值:char型数据自身对齐值为1字节,short型数据为2字节,int/float型为4字节,double型为8字节。(另外需要注意在 64位系统和32位系统下 指针类型和long类型 大小不同 32/64位系统下 4/8 字节大小)

     2) 结构体或类的自身对齐值:其成员中自身对齐值最大的那个值。

     3) 指定对齐值:#pragma pack (value)时的指定对齐值value。

     4) 数据成员、结构体和类的有效对齐值:自身对齐值和指定对齐值中较小者,即有效对齐值=min{自身对齐值,当前指定的pack值}。

 

对齐准则:

结构体字节对齐的细节和具体编译器实现相关,但一般而言满足三个准则:

     1) 结构体变量的首地址能够被其最宽基本类型成员的大小所整除;

     2) 结构体每个成员相对结构体首地址的偏移量(offset)都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节(internal adding);

     3) 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节{trailing padding}。

举例如下:

struct test1{
    char     a;
    double   b;
    int      c;
};

按照对齐准则: 第一条先不管, 因为第二条规则 double  b存储位置为结构体首地址偏移8字节, 按照第三条规则, 需要在int c 后面补齐4 字节, 所以整个结构体大小为 3*8 = 24 字节, 见下左图.  如果把int c 放到第二位的话,  对齐方式如下右图.

 

所以: 为了减少结构体对齐导致的内存消耗, 定义结构体时一般按照成员类型从大到小排列. (从小到大也行)

对齐的隐患:

数据类型转换:强转数据类型时可能会从奇数边界访问内存

处理器间数据通信:需要注意字节对齐和字节序的问题

 

如果出现对齐或者赋值问题可查看:

     1) 编译器的字节序大小端设置;

     2) 处理器架构本身是否支持非对齐访问;

     3) 如果支持看设置对齐与否,如果没有则看访问时需要加某些特殊的修饰来标志其特殊访问操作

 

更改对齐方式

     主要是更改C编译器的缺省字节对齐方式。   

     在缺省情况下,C编译器为每一个变量或是数据单元按其自然对界条件分配空间。一般地,可以通过下面的方法来改变缺省的对界条件:

使用伪指令#pragma pack(n):C编译器将按照n个字节对齐;

使用伪指令#pragma pack(): 取消自定义字节对齐方式。

 

另外,还有如下的一种方式(GCC特有语法):

__attribute((aligned (n))): 让所作用的结构成员对齐在n字节自然边界上。如果结构体中有成员的长度大于n,则按照最大成员的长度来对齐。

__attribute__ ((packed)): 取消结构在编译过程中的优化对齐,按照实际占用字节数进行对齐。

【注】__attribute__机制是GCC的一大特色,可以设置函数属性(Function Attribute)、变量属性(Variable Attribute)和类型属性(Type Attribute)。详细介绍请参考:    http://www.unixwiz.net/techtips/gnu-c-attributes.html

 

2. 栈内存对齐

在VC/C++中,栈的对齐方式不受结构体成员对齐选项的影响。总是保持对齐且对齐在4/8字节边界上。

也就是说变量的内存地址总是4/8的倍数

以多少字节对齐取决于是 32位 还是 64位, 具体的话又涉及到系统和硬件, 这里不多讲, 知道有这么个事儿就行.

 

3. 位域对齐

位域说明

有些信息在存储时,并不需要占用一个完整的字节,而只需占几个或一个二进制位。

位域是一种特殊的结构成员或联合成员(即只能用在结构或联合中),用于指定该成员在内存存储时所占用的位数,从而在机器内更紧凑地表示数据

 

位域在本质上就是一种结构类型,不过其成员是按二进位分配的。位域变量的说明与结构变量说明的方式相同,可先定义后说明、同时定义说明或直接说明。      

 

使用场景

1) 当机器可用内存空间较少而使用位域可大量节省内存时。如把结构作为大数组的元素时。

2) 当需要把一结构体或联合映射成某预定的组织结构时。如需要访问字节内的特定位时

 

对齐规则

位域成员不能单独被取sizeof值。

    C99规定int、unsigned int和bool可以作为位域类型,但编译器几乎都对此作了扩展,允许其它类型的存在。位域作为嵌入式系统中非常常见的一种编程工具,优点在于压缩程序的存储空间。

 

     1) 如果相邻位域字段的类型相同,且其位宽之和小于类型的sizeof大小,则后面的字段将紧邻前一个字段存储,直到不能容纳为止;

     2) 如果相邻位域字段的类型相同,但其位宽之和大于类型的sizeof大小,则后面的字段将从新的存储单元开始,其偏移量为其类型大小的整数倍;

     3) 如果相邻的位域字段的类型不同,则各编译器的具体实现有差异,VC6采取不压缩方式,Dev-C++和GCC采取压缩方式;

     4) 如果位域字段之间穿插着非位域字段,则不进行压缩;

     5) 整个结构体的总大小为最宽基本类型成员大小的整数倍,而位域则按照其最宽类型字节数对齐

 

注意事项

1) 位域的地址不能访问,因此不允许将&运算符用于位域。不能使用指向位域的指针也不能使用位域的数组(数组是种特殊指针)。

2) 位域不能作为函数返回的结果。

3) 位域以定义的类型为单位,且位域的长度不能够超过所定义类型的长度。例如定义int a:33是不允许的。

4) 位域可以不指定位域名,但不能访问无名的位域。

5) 位域的表示范围。

位域的赋值不能超过其可以表示的范围;

位域的类型决定该编码能表示的值的结果。

6) 带位域的结构在内存中各个位域的存储方式取决于编译器,既可从左到右也可从右到左存储。

7) 位域的实现会因编译器的不同而不同,使用位域会影响程序可移植性。因此除非必要否则最好不要使用位域。

8) 尽管使用位域可以节省内存空间,但却增加了处理时间。当访问各个位域成员时,需要把位域从它所在的字中分解出来或反过来把一值压缩存到位域所在的字位中。

 

四. linux内存分配对齐

GNU网站中把glibc源码下载下来,查看其 malloc.c文件,整理关键信息如下图

request2size负责内存对齐操作,MINSIZE是malloc时内存占用的最小内存单元,32位系统为16字节,64位系统为32字节,MALLOC_ALIGNMENT为内存对齐字节数,由于在32和64位系统中,size_t为4字节和8字节,所以MALLOC_ALIGNMENT在32位和64位系统中,分别为8和16.

 

实际上,对齐参数(MALLOC_ALIGNMENT)大小的设定需要满足以下两点:

1. 必须是2的幂

2. 必须是void *的整数倍

 

所以从request2size可知,在64位系统,如果申请内存为1~24字节,系统内存消耗32字节,当申请25字节的内存时,系统内存消耗48字节。而对于32位系统,申请内存为1~12字节时,系统内存消耗为16字节,当申请内存为13字节时,系统内存消耗为24字节

一般他们的差距是一个指针大小,计算公式是

max(MINSIZE,in_use_size) 

其中in_use_size=(要求大小+2*指针大小-指针大小)align to MALLOC_ALIGNMENT

(对于上面计算的由来可以参见glibc 内存池管理 ptmalloc这篇文章的第4节chuck部分以及搜一下malloc的内部实现源码 )

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

内存管理解析(2) 字节对齐详解 的相关文章

  • 如何“grep”连续流?

    可以用吗grep在连续的流中 我的意思是有点tail f
  • Snap-confine 具有提升的权限,并且不受限制,但应该受到限制。拒绝继续避免权限升级攻击

    我已经使用 snap 一段时间了 但最近升级后 当我尝试打开任何应用程序时 出现此错误 Snap confine has elevated permissions and is not confined but should be Refu
  • bash双括号问题

    我对 bash 脚本非常陌生 在使用双括号时遇到了问题 我似乎无法让它们在 Ubuntu Server 11 10 中工作 我的下面的脚本位于 if test sh 中 bin bash if 14 14 then echo FOO fi
  • 使用 C++ 输出字符串覆盖 Linux 终端上的最后一个字符串

    假设我有一个命令行程序 有没有办法让我说的时候 std cout lt lt stuff 如果我不做std cout lt lt n 在另一个之间std cout lt lt stuff 东西的另一个输出将覆盖同一行上的最后一个东西 清理行
  • 对 sf:: 的未定义引用

    我想用 C 制作 GUI 应用程序 发现 SFML 是一个不错的选择 幸运的是 我使用的是 Linux 所以 SFML 2 4 已经安装在我的系统上 所以我开始搜索一些教程并找到了一个制作简单窗口的教程 但是当我运行代码时 出现错误 提示未
  • Linux TCP服务器:在接受连接之前读取客户端的IP地址

    Related C Winsock API如何在接受连接之前获取连接客户端IP https stackoverflow com questions 716209 c winsock api how to get connecting cli
  • 如何使用 bash 脚本关闭所有终端,在每个终端中有效地按 Ctrl+Shift+Q

    我经常打开许多终端 其中一些正在运行重要的进程 例如服务器 而另一些则没有运行任何东西并且可以关闭 如果您按 重要 则会弹出确认提示Cntrl Shift Q在其中 如下所示 我想要一个 bash 脚本 它可以关闭所有终端 但将 重要 终端
  • /proc/PID 文件格式

    我想从中检索一些流程信息 proc目录 我的问题如下 中的文件是否有标准格式 proc PID 例如 有这个proc PID status文件与Name t ProcName在第一行 我可以在其他地方用空格代替这个文件吗 t或者类似的东西
  • 在中断时获取 current->pid

    我正在Linux调度程序上写一些东西 我需要知道在我的中断到来之前哪个进程正在运行 当前的结构可用吗 如果我在中断处理程序中执行 current gt pid 我是否可以获得我中断的进程的 pid 你可以 current gt pid存在并
  • Linux 文本文件操作

    我有一个格式的文件 a href a href a href a href 我需要选择 之后但 之前的文本 并将其打印在行尾 添加后 例如 a href http www wowhead com search Su a a a a a
  • grails 上的同步块在 Windows 上有效,但在 Linux 上无效

    我有一个 grails 应用程序 它依赖于服务中的同步块 当我在 Windows 上运行它时 同步按预期工作 但当我在 ams linux 上运行时 会出现 StaleObjectStateException 该问题在以下示例中重现 cla
  • 使用脚本自动输入 SSH 密码

    我需要创建一个自动向 OpenSSH 输入密码的脚本ssh client 假设我需要通过 SSH 进入myname somehost用密码a1234b 我已经尝试过 bin myssh sh ssh myname somehost a123
  • 如何在 Linux x86_64 上模拟 iret

    我正在编写一个基于 Intel VT 的调试器 由于当 NMI Exiting 1 时 iret 指令在 vmx guest 中的性能发生了变化 所以我应该自己处理vmx主机中的NMI 否则 guest会出现nmi可重入错误 我查了英特尔手
  • sqlite 插入需要很长时间

    我正在将不到 200 000 行插入到 sqlite 数据库表中 我只是在终端中通过 sqlite3 使用一个非常简单的 sql 文件 我打赌它已经运行了至少 30 分钟 这是正常现象还是我应该关闭该过程并尝试不同的方法 sqlite中的插
  • Gradle 1.3:build.gradle 不构建类

    这里有一个新问题 我有一个 build gradle 文件apply plugin java在其中 并与 java 项目 包关联 当我跑步时gradle build从命令行我得到 compileJava UP TO DATE process
  • 为什么 ld 无法从 /etc/ld.so.conf 中的路径找到库?

    我想添加 opt vertica lib64进入系统库路径 所以我执行以下步骤 1 添加 opt vertica lib64 into etc ld so conf 然后运行ldconfig 2 检查 bash ldconfig p gre
  • 错误:NVIDIA-SMI 失败,因为无法与 NVIDIA 驱动程序通信

    NVIDIA SMI 抛出此错误 NVIDIA SMI 失败 因为无法与 NVIDIA 通信 司机 确保安装了最新的 NVIDIA 驱动程序并且 跑步 我清除了 NVIDIA 并按照提到的步骤重新安装了它here https askubun
  • “grep -q”的意义是什么

    我正在阅读 grep 手册页 并遇到了 q 选项 它告诉 grep 不向标准输出写入任何内容 如果发现任何匹配 即使检测到错误 也立即以零状态退出 我不明白为什么这可能是理想或有用的行为 在一个程序中 其原因似乎是从标准输入读取 处理 写入
  • Linux 上的 Python 3.6 tkinter 窗口图标错误

    我正在从 Python GUI 编程手册 学习 Python GUI 某项任务要求我通过将以下代码添加到我的配方中来更改窗口图标 Change the main windows icon win iconbitmap r C Python3
  • python:numpy 运行脚本两次

    当我将 numpy 导入到 python 脚本中时 该脚本会执行两次 有人可以告诉我如何阻止这种情况 因为我的脚本中的所有内容都需要两倍的时间 这是一个例子 usr bin python2 from numpy import print t

随机推荐

  • 数据库——sql数据查询

    sql数据查询 单表查询 多表查询 联合查询UNION 连接查询 嵌套查询 子查询 复制表 判断查询 单表查询 查询全部数据 select from 表名 查询部分字段 select 字段1 字段2 from 表名 简单的条件查询 sele
  • Docker无法连接到docker守护程序

    本文翻译自 Docker can t connect to docker daemon After I update my Docker version to 0 8 0 I get an error message while enter
  • redux使用教程一 ——实现计数器

    文章目录 安装 概念介绍 action 和 action创建函数 reducer Store 计数器示例 安装 安装稳定版redux cnpm install save redux 安装redux绑定库和开发者工具 cnpm install
  • ofbiz Couldn't create server socket(/127.0.0.1:10523)

    start运行时报这个错误的话 只需把 framework webapp config url properties中的 这两个端口号改一下就可以了 需要改的地方已经标红 HTTPS Port Secure port port https
  • STM32的ADC介绍

    STM32的ADC精度是12位 它有18个通道 可以测量16路外部和2个内部信号源 各通道的A D转换可以单次 连续 扫描或间断模式执行 ADC的结果可以左对齐或右对齐方式存储在16位数据寄存器中 主要特征 12 位分辨率 转换结束 注入转
  • CGAL 读写.xyz格式的点云 编程

    CGAL 读写 xyz格式的点云 编程 在计算机图形学和计算几何中 点云是一个由大量离散点组成的数据集合 用于表示物体的表面或者场景的几何结构 点云数据可以通过不同的文件格式进行存储和交换 其中 xyz 格式是一种简单且常用的表示点云的文件
  • ctfshow简单题web1-15

    ctfshow萌新 目录 ctfshow萌新 web1 web2 4 web5 7 web9 web10 web11 web12 web13 web14 15 总结 这几题主要都是正则匹配字符过滤的绕过 基本步骤都是源码中查看过滤规则 gt
  • docker中运行redis主从机连接出现master_link_status:down的解决问题(含坑)

    使用命令配置主从复制出现主从机无法连接 在使用命令 slaveof host port 或者是 replicaof host port 命令配置redis主从复制时 从机出现master link status down提示 显示主机是do
  • 使用Yolov5 模型,训练自己的数据集这里以目标检测BDD数据集为例,跑出检测结果

    yolov5模型下载地址 GitHub ultralytics yolov5 YOLOv5 in PyTorch gt ONNX gt CoreML gt TFLite 下载完需要配置环境 yolov5的环境所需的包基本都收录在requir
  • 双链表-纯C语言(代码以及详细解释)

    目录 简介 使用 C 代码实现 可供CV大师参考 代码详细介绍及讲解 知识点密集 可能错误 大佬们评论区指点 doge保命 1 动态申请一个节点 2 打印 遍历链表 3 尾插数据 4 头插数据 5 头删数据 6 尾删数据 7 查找数组 返回
  • 初步理解Spring Security并实践

    Spring Security主要做两件事 一件是认证 一件是授权 1 Spring Security初体验 Spring Security如何使用 先在你的项目pom xml文件中声明依赖
  • 刷脸支付市场有没信心可以放心顾虑

    刷脸支付设备供不应求这一状态 本身就很能反映一个问题 刷脸支付市场很大 需求量很高 对刷脸支付市场没信心全部可以放心顾虑 刷脸支付即将迎来全面爆发 刷脸支付代理商抓住时机 刷脸支付即将迎来全面爆发阶段 想做刷脸支付代理商的朋友抓住时机 今年
  • 国家信息安全水平考试NISP一级模拟题

    1 下列关于用户口令说法错误的是 A 口令不能设置为空 B 口令长度越长 安全性越高 C 复杂口令安全性足够高 不需要定期修改 D 口令认证是最常见的认证机制 正确答案 C 2 下列关于木马病毒的特性 不正确的是 A 隐蔽性 B 主动传播性
  • 基于阿里云天池的飞猪平台用户行为分析——MySQL

    前言 本文是基于阿里云天池的飞猪平台用户行为分析 使用MySQL和Excel做数据分析 对输出结果使用Excel和PowerBI进行数据可视化 一 数据分析步骤 明确问题 理解数据 数据清洗 数据分析 数据可视化 二 明确问题 1 数据来源
  • 2019 CSS经典面试题(史上最全,持续更新中...)

    这些是我自己在学习过程中总结的一些知识点 本篇文章我将以面试题的形式分享给大家 希望对大家有所帮助 本文篇幅较长 您若认真看完 并且反复阅读 我相信对您的学习或者是面试 都会有一定帮助 同时希望大家批评指正 1 介绍一下标准的CSS的盒子模
  • Hadoop从零开始教程第一篇(在linux上安装hadoop集群centos7+hadopp3.2)

    Hadoop简介 Hadoop是Apache旗下的一套开源分布式计算平台 应用范围 利用服务器集群 根据用户的自定义业务逻辑 对海量数据进行分布式处理 核心组件 HDFS 分布式文件系统 高容错性 高伸缩性等允许用户将Hadoop部署在低廉
  • vue实现导出excel的两种方式

    需求说明 通过vue实现导出有两种方式 1 后端返回的是一个地址 直接拼接打开下载就行 2 后端返回的是文件流的形式 这个时候就需要在请求头还有返回值的地方设置一下 一 后端返回的是地址 页面代码
  • 条件数(condition number)

    首先引入维基上的解释 In the field of numerical analysis the condition number of a function with respect to an argument measures ho
  • COLMAP简明教程 重建 转化深度图 导出相机参数 导入相机参数 命令行

    COLMAP简明教程 导入指定参数 命令行 导出深度图 COLMAP是经典的3D重建 SfM 深度估计开源工作 配置和安装按下不表 本文主要从命令行的角度 对COLMAP的基本用法做教程 并备收藏和笔记 对指定图像进行重建和深度估计 准备好
  • 内存管理解析(2) 字节对齐详解

    很想贴出转载链接 找不到原来看的资料了 只有从个人记录的笔记上挪过来 如有错误请留言指正 目录 一 什么是字节对齐 二 为什么要字节对齐 三 有哪些对齐形式 1 结构体对齐 对齐值 对齐准则 对齐的隐患 更改对齐方式 2 栈内存对齐 3 位