为什么需要内存对齐?

2023-12-22

我知道这个问题已经被问过一千次了,我已经阅读了每一个答案,但我仍然不明白。我的 RAM 模型可能存在一些根本性错误,使我无法理解任何答案。

我从互联网上得到了所有这些小信息,但我就是无法将它们联系起来。

以下是我认为到目前为止所知道的:以 IA-32 架构为例,其字边界为 32 位(边界 = CPU 可以从内存读取的最大值?)。它将始终在其字边界内读取。

1)那么,无论我给它什么地址,它总是会读取4个字节?如果我在地址 x 处有一个简单的字符怎么办?它会从该地址读取 4 个字节,然后执行一些奇怪的操作以仅获取一个字节吗?

2)如果是这样,那么一个字符串(字符序列)n_chars * 4字节大吗?我很确定事实并非如此,但是我该如何解释“将始终读取其单词边界”呢?

3)内存对齐似乎只与数据结构有关。为什么?内存的其余部分是否未对齐?我的意思是物理空间、虚拟空间、内核空间等?

4) 为什么我只能在可被4整除的地址处存储32位值?我的意思是我知道它最终只能读取 32 位,但为什么它不能从奇数地址读取 32 位呢?比如这里有什么限制?

我只是很困惑请帮助我


在现代计算机中,内存是面向字节。每个字节都有自己的地址,可以单独从 RAM 中获取。为了您的程序,您可以假设获取一个字的行为就像获取以任意顺序组成它的字节,然后将它们组装成您加载到的寄存器中的一个字。

请注意,这是一个抽象。存储芯片通常以一次读取 8 个或更多字节的方式连接。 CPU 有一些电路可以将所有这些从机器代码中抽象出来。然而,这种抽象是leaky https://en.wikipedia.org/wiki/Leaky_abstraction这会导致许多影响:

  • 如果数据未符合其对齐要求,则内存访问可能会花费额外的周期,因为数据跨越的字数超出了所需的字数。通过充分对齐数据可以避免这种损失。
  • 当获取或写入对齐数据时,这会转化为硬件中的单个获取或存储。这样的获取或存储是atomic这是并发代码中的一个重要属性。当获取或写入未对齐的数据时,需要多次获取或存储,并且操作不再是原子的。
  • 有些 CPU 根本不支持读/写未对齐的内存,因为这可以简化电路设计。这种限制在当代硬件中变得越来越罕见。

现在,针对您的问题:

1)那么,无论我给它什么地址,它总是会读取4个字节?如果我在地址 x 处有一个简单的字符怎么办?它会从该地址读取 4 个字节,然后执行一些奇怪的操作以仅获取一个字节吗?

或许。这取决于您使用的硬件。但是,是的,如果您请求一个字节,您将只获得一个字节。您不应该关心硬件读取多少字节才能为您提供该一个字节。

2)如果是这样,那么一个字符串(字符序列)n_chars * 4字节大吗?我很确定事实并非如此,但是我该如何解释“将始终读取其单词边界”呢?

一个字符串通常是n_chars字节大。当您从字符串中读取一个字符时,您将获得一个字节。硬件可能会读取更多字节来满足您的请求,但这不是您需要关心的事情。请注意,Windows 有时使用 UTF-16 字符串,每个字符占用两个字节,但这种趋势尚未真正流行。

3)内存对齐似乎只与数据结构有关。为什么?内存的其余部分是否未对齐?我的意思是物理空间、虚拟空间、内核空间等?

每当考虑 RAM 中的数据时,内存对齐都很重要。该内存是否在内核或用户进程内部使用并不重要。 MMU 通常以保持对齐的方式映射内存,因此无论您使用物理内存还是虚拟内存都没有关系。磁盘上的数据没有这些对齐要求,但由于您使用的存储的扇区大小,其他性能特征可能适用。

4) 为什么我只能在可被4整除的地址处存储32位值?我的意思是我知道它最终只能读取 32 位,但为什么它不能从奇数地址读取 32 位呢?比如这里有什么限制?

如果从奇数地址读取 32 位,则会发生以下情况之一,具体取决于您的 CPU 和操作系统:

  1. 它只是有效
  2. 它可以工作,但速度有点慢
  3. CPU默默地忽略低2位并从相应的对齐地址读取(现在这种情况很少见)
  4. CPU 会抛出异常,如果不处理它就会导致程序崩溃
  5. CPU 会抛出异常,操作系统会捕获该异常来模拟内存访问。

您通常不应该假设会发生以下哪一种情况。切勿编写读取未对齐数据的代码。如果您需要读取未对齐的数据,请考虑单独读取每个字节,然后手动将字节重新组装成您想要的数据。

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

为什么需要内存对齐? 的相关文章

  • Codeigniter 处理大文件时允许的内存大小耗尽

    我发布此内容是为了防止其他人正在寻找相同的解决方案 因为我刚刚在这个废话上浪费了两天时间 我有一个 cron 作业 每天使用一个非常大的文件更新数据库一次 使用以下代码 if handle fopen dirname FILE uncomp
  • 序列化对于对象大小估计可靠吗?

    我使用序列化来估计对象使用的内存量 我已经读过this https stackoverflow com questions 426396 how much memory does a c net object use and this ht
  • JVM内存段分配

    好吧 我有一个关于 JVM 内存段的问题 我知道每个 JVM 都会选择稍微不同地实现这一点 但这是一个总体概念 在所有 JVM 中应该保持相同 一个在运行时不使用虚拟机执行的标准C C 程序在运行时有四个内存段 代码 堆栈 堆 数据 所有这
  • CPU寄存器和多任务处理

    我目前正在学习汇编 我很困惑 CPU 寄存器如何与多任务一起工作 所以在多任务系统中 CPU可以随时暂停某个程序的执行并运行另一个程序 那么在这一步中寄存器值是如何保存的呢 寄存器是压入堆栈还是以其他方式 CPU 寄存器如何与多任务一起工作
  • 阴影空间示例

    EDIT 我接受了下面的答案 并添加了我自己的代码的最终修订版 希望它向人们展示影子空间分配的实际示例 而不是更多的文字 编辑 2 我还设法在 YouTube 视频 所有内容 的注释中找到了一个调用约定 PDF 的链接 其中有一些关于 Li
  • std::aligned_alloc() 的重新分配等效项是什么?

    我发觉到std aligned alloc https en cppreference com w cpp memory c aligned alloc进入 C 17 我喜欢它 但是 当我需要重新分配时会发生什么 我可以手动执行此操作 假设
  • 为什么结构中“[0]byte”的位置很重要?

    0 byte在golang中不应该占用任何内存空间 但这两个结构体的大小不同 type bar2 struct A int 0 byte type bar3 struct 0 byte A int 那么为什么这个位置 0 byte这里重要吗
  • 如何将 x86 GCC 风格的 C 内联汇编转换为 Rust 内联汇编?

    我在 C 中有以下内联汇编 unsigned long long result asm volatile byte 15 byte 49 shlq 32 rdx orq rdx rax a result rdx return result
  • Java:为什么它使用固定数量的内存?或者它如何管理内存?

    JVM 似乎使用了一些固定数量的内存 至少我经常看到参数 Xmx 对于最大尺寸 和 Xms 对于初始大小 这表明 我感觉 Java 应用程序不能很好地处理内存 我注意到一些事情 即使一些非常小的示例演示应用程序也会加载大量内存 也许这是因为
  • 是否有其他方法可以释放 C 中动态分配的内存 - 不使用 free() 函数?

    我正在为测试而学习 我想知道这些是否等同于 free ptr malloc NULL calloc ptr realloc NULL ptr calloc ptr 0 realloc ptr 0 据我了解 这些都不起作用 因为 free 函
  • linux x86 汇编语言 sys_read 调用的第一个参数应为 0 (stdin)

    我正在编写一个简单的汇编程序来从标准输入读取 如 scanf 这是我的代码 section bss num resb 5 section txt global start start mov eax 3 sys read mov ebx 0
  • FreePascal x64 上系统单元函数的汇编调用

    我有一些 Delphi 汇编代码 可以在 Win32 Win64 和 OSX 32 上编译并正常工作 XE2 但是 由于我需要它在 Linux 上工作 所以我一直在考虑编译它的 FPC 版本 到目前为止 Win32 64 Linux32 6
  • 如何在程序中将自己缝合到自己的尾部,无限循环地封装 64KB 代码段?

    如果指令的顺序执行经过偏移量 65535 则8086将从同一代码段中的偏移量 0 处获取下一个指令字节 接下来的 COM 程序利用这一事实 不断将其整个代码 总共 32 个字节 缝合到自己的尾部 环绕在 64KB 代码段中 你可以称之为二元
  • Chrome 内存/垃圾收集问题

    我在使用 Chrome 时遇到内存 垃圾收集问题 我正在开发一个照片上传网站 该网站允许我的客户使用 HTML5 和文件 API 拖放照片进行上传 因此这在 IE 中不起作用 它仅适用于 Chrome 和 FF 我还没有在 Safari O
  • Android - WindowManager 导致崩溃并显示“窗口数超过最大 300”

    我看到我的日志软件中报告了此错误 但无法确定导致该错误的原因 或者 300 限制指的是什么 视图数或列表中可能显示的项目数 这就是我可以从日志中获取的全部内容 window count is over max 300 android vie
  • GCC的sqrt()编译后如何工作?使用哪种root方法?牛顿-拉夫森?

    只是对标准感到好奇sqrt 来自 GCC 上的 math h 我自己编码的sqrt 使用牛顿拉夫森来做到这一点 是的 我知道 fsqrt 但CPU是如何做到这一点的呢 我无法调试硬件 现代 CPU 中的典型 div sqrt 硬件使用 2
  • 如何使用 Bochs 运行汇编代码?

    我想使用 Bochs 作为 8086 模拟器 是否有捷径可寻 我想要的是类似 emu8086 的东西 http www emu8086 com http www emu8086 com 如果程序的初始部分适合 512 字节 并且您不介意将自
  • 跟踪 Linux 程序中活跃使用的内存

    我想跟踪各种程序在特定状态下接触了多少内存 例如 假设我有一个图形程序 最小化时 它可能会使用更少的内存 因为它不会重新绘制窗口 这需要读取图像和字体并执行大量库函数 这些对象仍然可以在内存中访问 但实际上并没有被使用 类似的工具top它们
  • 如何计算选择查询的最佳获取大小

    在 JDBC 中 默认获取大小为 10 但我想当我有一百万行时 这不是最佳获取大小 据我所知 获取大小太低会降低性能 但如果获取大小太高也会降低性能 我怎样才能找到最佳尺寸 这对数据库端有影响吗 它会占用大量内存吗 如果您的行很大 请记住
  • gdb查找行号的内存地址

    假设我已将 gdb 附加到一个进程 并且在其内存布局中有一个文件和行号 我想要其内存地址 如何获取文件x中第n行的内存地址 这是在 Linux x86 上 gdb info line test c 56 Line 56 of test c

随机推荐

  • XML 两个同名标签

    在我的 XML 文档中 我有两个同名的标签 都称为 item 我现在已经为此文档创建了一个 XML 架构 考虑到我有两个同名的标签 我的 XML 架构准确吗 XML文档
  • 无法在我自己的代码中将 CHOLMOD 与 CUDA 加速一起使用

    我正在尝试使用CHOLMOD with CUDA加速度SuiteSparse 4 4 4 我按照用户指南编译了它 我可以运行gpu sh under Demo文件夹成功 这表明GPU正在做部分工作 但是 当我尝试使用运行我自己的代码时CHO
  • 以编程方式加载 SSIS 包配置

    我正在 SSIS 中制作一个框架 用于从可配置文件夹加载文件并将它们与数据库中的逻辑作业相匹配 在此作业中配置了包名称 并在 SSIS 中我在运行时执行此包 我想根据加载的作业以编程方式加载此包的包配置 SSIS SQL Server 包配
  • 基于 SAML 断言的 SAML2 身份验证和授权

    我在用着spring security saml2 service provider针对 SAML IdP 验证我的 SpringBoot Web 应用程序 这有效 我还可以使用 REST 控制器访问 SAML 断言 Authenticat
  • H2数据库:使用jdbcTemplate插入记录时,列“ID”不允许为NULL

    我使用 hibernate 的 hbm2ddl 自动生成模式 这是我的域名 Entity public class Reader Id GeneratedValue strategy GenerationType AUTO Long id
  • 推送通知加密错误

    我在 PHP Laravel 应用程序中使用 Push Notifs 我创建了一个 pem 文件并对其进行了测试 在我的开发机器上使用它时 它可以正确推送到移动设备 当我现在将整个项目推送到生产服务器并启动 Pushnotif 调用时 我收
  • Spark:reduce和reduceByKey之间的语义差异

    在 Spark 的文档中 它说 RDDs 方法reduce http spark apache org docs latest api scala index html org apache spark rdd RDD需要一个结合与交换的二
  • 居中裁剪图像以适当的尺寸在 ImageView 上设置

    我正在使用相机 API 来拍照 我必须根据我的图像视图大小打开不同尺寸的相机 我正在关注我们在 Android sdk sample adroid 18 中获得的名为 ApiDemo 的示例项目 我所做的更改不是在 setcontentvi
  • 检查日期时间变量是今天、明天还是昨天

    我不知道如何检查日期时间变量是今天 明天还是昨天 我在类成员中没有找到方法 final now DateTime now final today DateTime now year now month now day final yeste
  • Highcharts - 柱形图重画动画

    我正在尝试使用新的数据数组更新现有的数据系列并调用redraw完成后即可运行 虽然这工作得很好 但我不太满意 因为我想要一种增长 收缩的过渡 我见过一个Highcharts 的示例 http www highcharts com studi
  • Angular 7:自定义异步验证器

    我正在尝试为我的注册表单创建一个自定义异步验证器 它会检查电子邮件是否已存在 如果电子邮件不存在 后端返回 404 如果存在 则返回 200 无法更改此旧代码 我找到了几个教程 但没有找到使用最新 rxjs 库的教程 我创建了这个验证类 e
  • Play 2.2 应用程序在 Heroku 上崩溃

    从 Play 2 0 4 迁移到 Play 2 2 0 后 在 Heroku 上部署时出现此错误 Oct 15 13 23 12 heroku web 1 Starting process with command target unive
  • 检测单个图像中的多个图像

    我需要帮助来识别边界并将图像与原始图像进行比较 我需要关于如何通过处理或 matlab 或任何初学者实现这一目标的指导 例如 看下图 原图 The Multiple Image 您展示的 多图像 很容易使用简单的图像处理来处理 不需要模板匹
  • 在我的自定义 android 视图中添加自定义字符串属性

    我有一个从表布局派生的自定义视图 我需要声明 String 属性 Title 如下所示
  • Android 3.1 构建 gradle 4.4 配置项目 ':app' 时发生错误

    当我使用模拟器 api26 错误时 我没有使用 kotlin 因为不是导入 kotlin 而是构建 api gt 26 错误 gt kotlin KotlinNullPointerException 无错误消息 com android bu
  • MySQL大量“SET autocommit=0/1”查询

    我正在我们的系统上运行一些负载测试 我注意到正在执行大量 SET autocommit 0 和 SET autocommit 1 查询 1 分钟内大约有 25 000 个 我试图找出造成这种情况的原因以及如何消除它 我们使用以下技术 MyS
  • Qt Creator 将其设置保存在哪里?

    我想找到 Qt Creator 保存所有设置 文本编辑器首选项 语法突出显示等 的文件夹 以便我可以备份它们 有人知道他们在哪里吗 See QtCreator 快速浏览 http doc qt io qtcreator creator qu
  • 如何从XML获取Dataset中的多个表

    我正在读取数据集中的 XML 以下是我的 XML 结构 XML
  • Spring Boot - 从 webjar 覆盖索引页面

    在我的项目中 我使用 swagger ui 库 它在类路径的根目录中有 index html 文件 以这样的方式这个index html当我点击 root url 时 它会成为我的应用程序的起始页 但我想使用我的自定义 Groovy 模板i
  • 为什么需要内存对齐?

    我知道这个问题已经被问过一千次了 我已经阅读了每一个答案 但我仍然不明白 我的 RAM 模型可能存在一些根本性错误 使我无法理解任何答案 我从互联网上得到了所有这些小信息 但我就是无法将它们联系起来 以下是我认为到目前为止所知道的 以 IA