【C++】025、内存对齐

云平台一键部署llama.cpp运行GLM5.1实战指南 LLM推理部署本质上是模型、运行时与硬件环境的三方协同问题。llama.cpp作为轻量级C++推理框架,凭借低依赖、高可控性成为边缘与云边协同场景的首选;而GLM5.1作为支持32K上下文的国产强推理模型,其rope-theta=1000000、attention_bias=True等定制化配置,与llama.cpp原生行为存在隐式冲突,导致加载失败、输出乱码或OOM频发。本文聚焦‘云平台一键部署’这一工程落地核心诉求,系统解析GPU卸载策略、GGUF量化选型(Q3_K_M优于Q4_K_M)、上下文内存对齐 阅读详情

一、内存对齐,本质上是CPU访问内存的硬件约束

  • CPU并不是以字节为单位来读取内存,而是以字(Word)为单位(4字节或8字节,根据电脑型号不同决定)。

  • 内存对齐要求数据的起始地址必须是其自身大小的整数倍。(比如int占4字节,则起始地址必须能被4整除)

  • 这不是C++语法限制,而是CPU指令集的物理硬性要求与性能要求。

二、内存对齐的原因

1、硬件限制

  • 像ARM、MIPS这类RISC(精简指令集计算机)架构的CPU,如果读取一个int但地址是奇数对齐,会直接触发硬件异常,导致进程崩溃。

  • 而x86,x64这种CISC(复杂指令集计算机)架构的CPU,能容忍未对齐访问,但在内部需要将一次读取拆解成两次内存总线事务。

2、性能损耗

  • 假设一个int(4字节)存放在地址0x1001未对齐的地址上,CPU需要先读取0x1000~0x1003这4个字节,再读取0x1004~0x1007这4个字节,然后再通过移位和拼接操作拼出正确的int值。

  • 而如果放在异对齐的0x1000地址,cpu只需要一条指令即可读取0x1000~0x1003这4个字节的数据

  • 对齐访问时原子操作,未对齐访问时组合操作,这就是性能差距的根源所在

3、缓存行隔离

  • 现代CPU以64字节缓存行为单位来加载数据,对齐能确保一个数据不会横跨两个缓存行,避免多次内存加载,并防止伪共享带来的并发性能暴跌。

三、内促对齐规则

1、编译器默认对齐规则

char:对齐到 1 字节(任意地址)。
short:对齐到 2 字节(地址 % 2 == 0)。
int:对齐到 4 字节(地址 % 4 == 0)。
double:对齐到 8 字节(地址 % 8 == 0)。
指针(64位):对齐到 8 字节。

2、结构体内存对齐规则

  • 结构体的大小必须是最大成员对齐要求的整数倍,并且结构体中每个属性都要求具有最大长度的空间对齐

  • 示例:

#include <iostream>

// ========== 结构体 A(内存浪费严重) ==========
struct A {
    char c;    // 1 字节,偏移 0
               // 填充 3 字节(偏移 1~3),为了对齐下面的 int
    int i;     // 4 字节,偏移 4(能被4整除)
    char d;    // 1 字节,偏移 8
               // 尾部填充 3 字节(偏移 9~11),为了让整个结构体大小是 4 的倍数
};
// sizeof(A) = 12 字节
// 内存布局: [c][   ][   ][   ][i][i][i][i][d][   ][   ][   ]

// ========== 结构体 B(优化内存布局) ==========
struct B {
    int i;     // 4 字节,偏移 0
    char c;    // 1 字节,偏移 4
    char d;    // 1 字节,偏移 5
               // 尾部填充 2 字节(偏移 6~7),让整体是 4 的倍数
};
// sizeof(B) = 8 字节
// 内存布局: [i][i][i][i][c][d][   ][   ]

int main() {
    std::cout << "A 大小: " << sizeof(A) << std::endl;  // 输出 12
    std::cout << "B 大小: " << sizeof(B) << std::endl;  // 输出 8
    // 结论:仅仅调整成员顺序,B 比 A 节省了 33% 的内存!
}
  • 结构体对齐操作是先填充在对齐,而且是每个属性都按照最大字节属性的空间来填充。

  • 所以对结构体内存优化操作:可以先把占用空间大的成员放在前面,小的放在后面,这样填充和总的结构体大小会变短。

四、内存对齐控制工具

1、alignof与alignas

  • alignof可以查询属性对齐要求的大小,alignas可强制指定对齐的大小

// 查询类型的对齐要求
std::cout << alignof(int) << std::endl;   // 输出 4
std::cout << alignof(double) << std::endl; // 输出 8

// 强制指定对齐(比如 SIMD 需要的 16 字节对齐)
struct alignas(16) AlignedStruct {
    float data[4];
};
std::cout << sizeof(AlignedStruct) << std::endl; // 16(对齐到16的倍数)
std::cout << alignof(AlignedStruct) << std::endl; // 16

2、#pragma pack 强制压缩结构体

  • 取消内存填充,多用于网络协议封包与读写二进制文件头

#pragma pack(push, 1)  // 将对齐系数强制设为 1(最紧凑)
struct NetworkPacket {
    char type;   // 1 字节
    int seq;     // 本来是4对齐,现在紧挨着 type,偏移 1
    short len;   // 紧挨着
};
#pragma pack(pop)   // 恢复默认对齐

// sizeof(NetworkPacket) = 1 + 4 + 2 = 7 字节(无任何填充)

3、attribute无填充设置

struct __attribute__((packed)) GccPacked {
    char c;
    int i;
};
// 同样无填充,大小 = 5

五、new与malloc底层内存对齐解析

  • malloc与operate new保证返回的地址满足当前平台最严格的对齐要求,也就是16字节,可兼容long double类型和SIMD,满足一条指令可同时处理多条数据的操作

  • 当new int时,返回的地址一定是4的倍数,所以即使我们写char *p = new char[1]时,内存的起始地址也是16字节对齐的。

【025】C++对C的扩展之引用(reference):让你的代码“指哪打哪” 引用是一个别名,可以将一个变量与另一个变量关联起来。通过引用,我们可以使用两个不同的名称访问相同的数据。引用必须在定义时初始化,一旦引用被初始化为一个对象,它就不能再绑定到另一个对象上了。引用作为函数参数传递时,可以避免复制大型对象的开销,并且可以直接修改原始对象。可以使用const修饰符使引用成为只读引用,这样就无法通过该引用修改原始数据。引用还可以返回函数中的值或对象,在这种情况下,函数返回类型必须是引用类型。指向常量的指针和常量引用之间有所不同:前者可重新赋值而后者不能重新赋值。 阅读详情

相关推荐

手写C++飞机大战:掌握游戏循环、内存管理与跨平台渲染

游戏开发中的核心概念——游戏主循环、对象生命周期管理、帧同步机制和跨平台渲染——是构建任何交互式应用的基础。理解固定时间步长(Fixed Timestep)原理,能避免物理模拟失真;掌握 `std::unique_ptr` 与手动内存控制的边界,有助于规避循环引用与悬垂指针;而基于 ANSI 转义序列或 Win32 GDI 的轻量渲染层,则揭示了图形抽象背后的真实系统调用路径。这些技术价值不仅适用于小游戏开发,更广泛支撑着引擎开发、嵌入式 GUI、实时仿真等场景。本文以纯 C++11 实现的飞机大战为载体,

weixin_34112181的博客 951

Linux C++ 025-STL之string容器

本节关键字:Linux、C++、容器、string 相关库函数:find、rfind、replace、append、insert等

Tianwx的博客 664

从零开始VCS+Verdi 安装过程

从零开始VCS+Verdi 安装及破解过程 主要参考:VCS+Verdi 安装及破解过程(CentOS7)-----FPGA开发 1. 安装文件结构 –vcs-mx_vL-2016.06 –verdi_vL-2016.06-1 –scl_v11.9 #此程序统一管理license等破解文件 –SynopsysInstaller.rar #此程序用于安装以上3个程序 –sc...

Ztrans的博客 2万+

C++-025-变量的存储类别

C+±025-自动变量与静态变量-2020-3-9 对它们分配和释放存储空间是由编译系统自动处理的,这类局部变量称为自动变量。自动变量用关键字auto作存储类型的说明。例如 auto int a; auto 也可以自动省略,auto不写则隐含确定为"自动存储类别",它属于动态存储类别。过去我们定义的变量都没有说明为auto,都隐含确定为自动变量。所以,上例等价于 int a; 有时希望函...

cloud 1757

Proxmox VE(PVE)与UPS联动配置:实现智能断电保护方案

本文详细介绍了为Proxmox VE (PVE)服务器配置UPS智能断电保护的完整方案。通过安装和配置apcupsd软件,实现PVE与UPS的联动,可在市电中断、电池电量不足时自动触发安全关机流程,有效保护虚拟机数据与服务连续性。文章涵盖了硬件选择、软件配置、策略设定及实战测试指南,并扩展了网络共享UPS的高级应用。

python9snake的博客 509

Vivado实战:UltraScale/UltraScale+器件eFUSE寄存器配置与安全编程全解析

本文详细解析了Xilinx UltraScale/UltraScale+器件中eFUSE寄存器的配置与安全编程方法。从芯片唯一身份标识到加密密钥烧录,再到用户寄存器的灵活应用和安全控制寄存器的配置技巧,全面介绍了如何利用eFUSE功能提升硬件安全性。文章还提供了JTAG接口安全管理和NKZ文件备份方案,帮助开发者避免常见陷阱,确保安全编程的可靠性。

weixin_42535703的博客 428

025-C++中引用

#include <iostream> using namespace std; /** 引用变量是一个别名,也就是说,它是某个已存在变量的另一个名字。 一旦把引用初始化为某个变量,就可以使用该引用名称或变量名称来 指向变量。 一: C++ 引用 vs 指针 引用很容易与指针混淆,它们之间有三个主要的不同: 不存在空引用。引用必须连接到一块合法的内存。 一旦引用被初始化为一个对象,就不能被指向到另一个对象。指针可以在任何时候指向到另一个对象。 引用必须在创建时被初始化。指针可以在任何.

好好学习,天天向上 149

四足机器人——机械结构

目录 一、四足机器人腿型: 1、并联腿 2、串联腿 3、 腿的布局(关节配置) 二、四足机器人足端设计: 三、四足机器人膝关节驱动: 1、皮带轮驱动: 2、四连杆或者推杆驱动 四、四足机器人机械整体结构设计细节 一、四足机器人腿型: 1、并联腿 优点:受力角度来说,并联腿比串联腿好,并联腿较为灵活。 2、串联腿 优点:运动范围大 3、 腿的布局(关节配置) 为了使机器人具有较好的稳定性,一般会采用比较低的重心。这就导致了机器人腿的髋关节位置需要位于机器人身体的两侧..

m0_58585940的博客 3万+

c++编程练习 025:这是什么鬼delete

北大程序设计与算法(三)测验题汇总(2020春季) 描述 程序填空输出指定结果 #include <iostream> using namespace std; class A { public: A() { } // 在此处补充你的代码 }; class B:public A { public: ~B() { cout << "destructor B...

计算机科学与技术专业学生的成长之路 1977

MQTT在智能家居中的实战:用Android手机控制ESP8266设备(基于EMQX)

本文详细介绍了如何利用MQTT协议构建一个完整的智能家居控制系统,通过Android手机App远程操控ESP8266设备。文章提供了从EMQX服务器部署、ESP8266端Arduino固件开发到Android客户端搭建的完整实战指南,并深入探讨了系统联调、稳定性优化与安全加固等关键环节,为物联网开发者提供了一套可复用的解决方案。

ujm567890的博客 457

Claude Code 从入门到精通,通过实战项目穿插 Agent Skills、MCP、Hooks、子代理、插件等十五个知识点

本文介绍了Claude Code的高级使用技巧,通过一个个人简历网站实战项目,详细讲解了15个核心知识点。主要内容包括:三种权限模式(默认/编辑/计划)的使用与切换;历史会话管理(/resume、/rename、/clear命令);会话回滚功能(/rewind);以及危险参数--dangerously-skip-permissions的注意事项。文章还演示了如何通过计划模式拆分代码文件,并强调了在复杂任务中仔细检查规划步骤的重要性。这些技巧能帮助开发者更高效地使用Claude Code完成项目开发。

1788

025:这是什么鬼delete

025:这是什么鬼delete 题面 描述 程序填空输出指定结果 #include <iostream> using namespace std; class A { public: A() { } // 在此处补充你的代码 }; class B:public A { public: ~B() { cout << "destructor B" << endl; } }; int main() { A * pa; pa = new B;

ACMer_WarYan 434

Android Audio最全面试题及参考答案(7万字长文)

在 Android 音频系统中,应用通过框架层的 API 发出音频请求,这些请求经过音频服务层的处理,传递到 HAL 层,再由 HAL 层调用音频驱动层与硬件进行交互,最终实现音频的播放、录制等功能。在 Android 音频系统中,应用通过框架层的 API 发出音频请求,这些请求经过音频服务层的处理,传递到 HAL 层,再由 HAL 层调用音频驱动层与硬件进行交互,最终实现音频的播放、录制等功能。音频播放完成事件:当使用 MediaPlayer 等音频播放类播放音频时,音频播放完成后会触发这个事件。

大模型大数据攻城狮的专栏 2604

025-C++ 数据结构

接下来,我们将进一步深入探讨数据结构的高级应用,包括复杂数据结构的实现、性能对比、多维数据结构、以及 STL 容器的底层原理。C++ 提供了多种数据结构,通过标准模板库(STL)和用户自定义的实现,可以满足不同场景下的存储和处理需求。数据结构是组织和管理数据的一种方式,是高效算法设计的基础。通过结合 STL 和自定义实现,C++ 提供了极大的灵活性和效率,能够满足几乎所有的数据结构需求。C++ 提供了强大的数据结构和 STL 容器,可以根据实际需求灵活选择合适的数据结构。更适合动态大小的二维数组。

小宝哥Code的专栏 894

Python数据分析全流程指南:从数据采集到可视化呈现的实战解析

在数字化转型浪潮中,数据分析已成为企业决策的核心驱动力。Python凭借其丰富的生态库和简洁的语法,成为数据分析师的首选工具。本文将以实战案例为脉络,拆解数据分析全流程的关键环节,通过具体代码和场景说明如何用Python完成从数据采集到可视化呈现的完整链路。

这家伙很懒,什么都没有留下 1681

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

025 - C++ 接口(纯虚函数)

这就是纯虚函数整个的工作原理,它知道任何 Printable 的东西,它们都有一个 GetClassName 函数去调用,如果你不实现这个函数,你就不能实例化这个类。这就是 C++ 中的接口,也就是 C++ 中的纯虚函数,它是非常有用的一个工具,可以被用在刚才的这个场景下,如果想要确保类都有一个特定的方法,那么可以将这个类作为参数放入一个通用的函数中,然后就可以调用这个方法或者做其他事情。本期内容就是这些,下期再见。

九灵猴君的博客 753

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

025-lz4

LZ4技术调研报告,包含核心算法解析、优化参数分析及完整C++实现

zhengtianzuo的博客 653

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

C++ L1-025. 正整数A+B

L1-025. 正整数A+B   本题的目标很简单,就是求两个正整数A和B的和,其中A和B都在区间[1,1000]。稍微有点麻烦的是,输入并不保证是两个正整数。 输入格式:   输入在一行给出A和B,其间以空格分开。问题是A和B不一定是满足要求的正整数,有时候可能是超出范围的数字、负数、带小数点的实数、甚至是一堆乱码。   注意:我们把输入中出现的第1个空格认为是A和B的分隔。题目保证至少...

我是菜鸡 4181

把文件读到内存中然后使用内存加载

把文件读到内存中然后使用内存加载 分两种方式实现C++和C   view sourceprint? 001.int read_dll_memory_load (TCHAR str_dll_path[],char str_export_fun[]) //用C++的方式把文件读到内存加载 002.{  003.filebuf *pbuf;  004.i

u012547790的专栏 5352

025 、new和delete的基本使用,是c++的操作符

/* new和delete的基本使用,是c++的操作符 结论: new不但可以分配内存,还可以初始化对象 malloc不会调用类的构造函数 free不会调用类的析构函数 */ #if 1 class Test { public: Test(int _a) { a = _a; cout &amp;lt;&amp;lt; &quot;构造函数执行&quot; &amp;lt;&amp;lt; endl; } ~Te...

吾竹清风2017 290

【C++】内存泄漏排查

内存泄漏影响程序的稳定性运行,并且在程序运行过程中,并不会报错误,需要借助专用的内存泄露工具进行检测。工具:CLion and AddressSanitizer。

个人笔记仅供本人查阅参考 928

C++ Cookbook by Eric

按照来源的不同,有两种类型的头文件:自己编写的头文件和标准库(编译器或者其他库的头文件);对于自己编写的头文件使用。对于标准库头文件使用。

墨门 2375

CPlusPlus - #025 malloc/free和new/delete

malloc/free和new/delete

AlanL的专栏 408

《你真的了解C++吗》零 总纲

你真的了解C++吗——不一样的100个概念》

腾TO的技术博客 891

L1-025 正整数A+B (15 分)

L1-025 正整数A+B (15 分) 题的目标很简单,就是求两个正整数A和B的和,其中A和B都在区间[1,1000]。稍微有点麻烦的是,输入并不保证是两个正整数。 输入格式: 输入在一行给出A和B,其间以空格分开。问题是A和B不一定是满足要求的正整数,有时候可能是超出范围的数字、负数、带小数点的实数、甚至是一堆乱码。 注意:我们把输入中出现的第1个空格认为是A和B的分隔。题目保证至少存...

黑色吊椅的博客 4981

InnoDB 内存结构总览:Change Buffer、AHI 与 Log Buffer

本文系统梳理InnoDB内存结构中的ChangeBuffer、Adaptive Hash Index(AHI)与LogBuffer。ChangeBuffer缓存二级索引页不在内存时的变更,减少随机IO,仅在页加载时合并;聚簇索引修改立即执行,因数据本身不可延后。AHI基于高频等值查询自动构建哈希索引,加速定位,仅支持等值操作。LogBuffer为redo log内存缓冲,配合磁盘日志实现崩溃恢复。三者均服务于性能优化,其中ChangeBuffer与AHI共享BufferPool空间,而LogBuffer独立

bksczm的博客 284
上一篇: 【C++】024、new[]与delete[]配对使用
下一篇: 【C++】026、C++内存分布:全局变量、局部变量、static变量、const常量
Tim_10
博客等级 码龄2年 162粉丝 106原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值