netcore高级知识点,内存对齐,原理与示例

news2024/9/23 3:28:58

最近几年一直从事物联网开发,与硬件打交道越来越多,发现越接近底层开发对性能的追求越高,毕竟硬件资源相对上层应用来实在是太缺乏了。今天想和大家一起分享关于C#中的内存对齐,希望通过理解和优化内存对齐,可以帮助大家更好的提高程序性能以及资源利用效率。

01什么是内存对齐

内存对齐指把数据存储在内存中时,需要按照某种特定规则进行存储,使其内存存储在符合特定边界要求的内存地址上。而内存对齐主要目的则是减少CPU内存操作次数,提高内存操作效率,并提升CPU缓存命中率,从而提升整体性能。

02内存对齐原则

内存对齐原则包含两部分:内存对齐边界和内存对齐规则。

① 内存对齐边界:数据存储在内存中的起始内存地址必须满足条件。例如,8字节对齐则要求数据的起始内存地址必须是8的倍数;
② 内存对齐规则:不同的硬件平台内存对齐规则也各有差异,比如:x86、x64架构在内存对齐方面比较宽松,而ARM、RISC-V架构则相对比较严格;一般32位处理器要求4字节对齐,而64位处理器要求8字节对齐;

因此不同的CPU架构和平台则内存对齐规则也各有不同,而这些差异也都是为了使数据在内存中的布局更加符合CPU操作方式,从而提高程序执行效率。

03C#中的内存对齐

1、“托管代码”和“非托管代码”

托管代码:执行过程交给运行时CLR管理的代码,运行时CLR负责提取托管代码并编译成机器代码最后执行,同时运行时CLR还负责自动内存管理、安全边界和类型安全等重要服务。

“非托管代码”:即不被运行时CLR管理的代码,比如运行C/C++语言编写的代码,而此时开发任意就需要亲自处理很多事情,比如内存管理、垃圾回收、安全问题等等。

因此一般对于托管代码来说,内存的分配以及对齐策略都被运行时CLR一手包办了,无需我们过多关注,而如果需要通过P/Invoke和COM互操作来调用非托管代码则需要开发者自己处理内存对齐策略了。

当然也不是说纯托管代码就没有对内存对齐操作空间了,只是相对来说与非托管代码交互时使用内存对齐操作空间更大。

2、StructLayoutAttribute特性

无论托管内存还是非托管内存,都可以用StructLayoutAttribute特性来对其进行内存布局控制,简单来说对于托管代码可以使用LayoutKind枚举值Explicit进行显示控制,而对于非托管代码LayoutKind枚举值都可以控制。

04示例-字段顺序影响内存占用大小

我们用StructLayout(LayoutKind.Sequential标记OriginalLayout结构体,看看每个字段的布局情况及其与占用内存总大小之间的关系,先来看下面一段代码:

using System.Runtime.InteropServices;
namespace CSharp
{
    public class MemoryLayout
    {
        [StructLayout(LayoutKind.Sequential)]
        public struct OriginalLayout
        {
            public long LongField1;
            public short ShortField;
            public byte ByteField1;
        }
        public static void Run()
        {
            Console.WriteLine($"OriginalLayout LongField1 偏移量: {Marshal.OffsetOf(typeof(OriginalLayout), "LongField1")} ");
            Console.WriteLine($"OriginalLayout ShortField 偏移量: {Marshal.OffsetOf(typeof(OriginalLayout), "ShortField")} ");
            Console.WriteLine($"OriginalLayout ByteField1 偏移量: {Marshal.OffsetOf(typeof(OriginalLayout), "ByteField1")} ");
            Console.WriteLine($"OriginalLayout 总大小: {Marshal.SizeOf(typeof(OriginalLayout))} bytes");
            Console.ReadKey();
        }
    }
}

我们使用Marshal.OffsetOf计算每个字段偏移量,即第一个字段偏移量表示其内存地址为0,则第二个字段偏移量表示为其相对第一个字段内存地址值的相对值,使用Marshal.SizeOf计算类型所占内存总大小。
如下图是上面代码运行结果:
在这里插入图片描述
首先说下long类型为8字节、short类型为2字节、byte类型为1字节,再来详细说下每个值怎么来的。

首先因为LongField1是第一个字段所以为0,并且因为long类型为8字节,所以LongField1使用了0-7内存地址段,所有第二个字段ShortField偏移量为8,因此ShortField使用了8-9内存地址段,所以第三个字段ByteField1偏移量为10。

那为什么总大小不是8+2+1=11字节,而16字节呢?这是因为对于类型的对齐方式默认会以其最大的元素对齐方式为准,并且整个类型大小是最大元素大小的整数倍,因此这里的总大小是8的倍数,因为2+1并没有占满8字节,因此ByteField1后面被自动填充了5个字节,以此达到对齐要求。所以最后就是8+2+1+5(自动填充)=16字节。

然后我们把LongField1和ShortField两个字段调整一下位置,再来看看运行结果:

public class MemoryLayout
{
    [StructLayout(LayoutKind.Sequential)]
    public struct OriginalLayout
    {
        public short ShortField;
        public long LongField1;
        public byte ByteField1;
    }
    public static void Run()
    {
        Console.WriteLine($"OriginalLayout ShortField 偏移量: {Marshal.OffsetOf(typeof(OriginalLayout), "ShortField")} ");
        Console.WriteLine($"OriginalLayout LongField1 偏移量: {Marshal.OffsetOf(typeof(OriginalLayout), "LongField1")} ");
        Console.WriteLine($"OriginalLayout ByteField1 偏移量: {Marshal.OffsetOf(typeof(OriginalLayout), "ByteField1")} ");
        Console.WriteLine($"OriginalLayout 总大小: {Marshal.SizeOf(typeof(OriginalLayout))} bytes");
        Console.ReadKey();
    }
}

在这里插入图片描述

这里为什么又是24字节呢?

首先虽然ShortField只占了2字节,使用了0-1内存地址段,但是LongField1并不能从2内存地址值开始排版,因为每个字段必须与其自身大小的字段或类型的对齐方式对齐,也就是说LongField1占8字节,那么其内存地址起始值也要是8的整数倍,因此LongFiled1使用了8-15内存地址段,而ShortField和LongFiled1之间会被自动填充6个字节,同样的ByteField1后面也被自动填充7个字节,因此总大小为24字节。

这里只是举了个小例子来展示字段顺序不同,对最终类型所占内存总大小的,这也给我们设计低内存消耗程序设计提供了空间。

当然这里只是简单使用了StructLayout,还Pack属性,以及Explicit和FieldOffset,还有CharSet、MarshalAs等复杂的功能都没有介绍,有兴趣的可以深入研究研究。本文只是简单内存对齐的原理原则以及简单的内存优化,后面有机会再给大家深入介绍。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2097125.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

深度学习模型量化方法

深度学习模型量化方法 (qq.com)

【hot100篇-python刷题记录】【回文链表】

R7-链表篇 思路: 转回文数组法 链表转数组,再使用双指针判断是不是回文数组即可。 wkao?!根本不用双指针判断是否回文数组,只需要倒序判断布尔值即可。(牛啊牛啊) # Definition for singly-linked list. # class…

LIN总线CAPL函数—— 更新特定报文数据(linUpdateResponse)

🍅 我是蚂蚁小兵,专注于车载诊断领域,尤其擅长于对CANoe工具的使用🍅 寻找组织 ,答疑解惑,摸鱼聊天,博客源码,点击加入👉【相亲相爱一家人】🍅 玩转CANoe&…

激光测距模组光轴调试怎么调

激光测距模组作为精密的测量工具,其光轴调试是确保测量精度的重要环节。正确调试光轴不仅能够提升测量的准确性,还能延长设备的使用寿命。以下将由鑫优威给大家详细介绍激光测距模组光轴调试的步骤及注意事项。 一、准备工作 在进行光轴调试前&#xff0…

[米联客-XILINX-H3_CZ08_7100] FPGA程序设计基础实验连载-24 TPG图像测试数据发生器设计

软件版本:VIVADO2021.1 操作系统:WIN10 64bit 硬件平台:适用 XILINX A7/K7/Z7/ZU/KU 系列 FPGA 实验平台:米联客-MLK-H3-CZ08-7100开发板 板卡获取平台:https://milianke.tmall.com/ 登录“米联客”FPGA社区 http…

非标机械设计项目“规范”笔记

2.自动化设备开发特点与技术文件输出 2.1自动化设备 自动化设备 工业自动化设备类型:标准自动化、非标自动化 载具和治具 焊接治具---汽车行业用的多 压装、压合治具---3C行业 治具种类: 电木:测试治具箱体&#xf…

Mac系统App打包成dmg文件总结

使用软件:BetterZip 操作步骤如下: 打开BetterZip 将想要打包的App拖入当前界面 选中文件点击文件-另存为 修改保存位置和压缩格式,点击存储即可 保存完成后修改文件名即可

关联模块的查询列表勾选数据,新建带出勾选数据

在模块找到页面拓展,新建按钮,代码在链接目标地址中写 获取当前勾选数据的id,将ID拼接到弹窗地址上 var CheckedCheckboxId _xtable_CheckedCheckboxId();//勾选中的checkid var result CheckedCheckboxId.replace(/^,|,$/g, ""); window.ope…

哪种类型的耳机不伤耳朵?五款口碑绝佳机型安利!

​要说最不伤耳朵的耳机,那肯定得是开放式耳机了!开放式耳机现在超火,因为它们戴起来舒服,音质又棒,让喜欢音乐和运动的朋友们超爱。特别是那些边运动边听歌的人,开放式耳机简直是完美。它们戴着稳&#xf…

网站注册流程是怎样的

网站注册流程是一项关键的操作,对于用户来说,这是接触和利用公司服务的第一步。一个简单、清晰的注册流程能够提高用户体验,增强用户对公司的信任感。下面是一个通用的公司网站注册流程,以及一些设计原则,以确保注册过…

NB6L295M MCU 设计参考

NB6L295M 2.5V / 3.3V 双通道可编程时钟 / 数据差分 CML 的延迟输出多电平输入,带内部终端;NB6L295M 是一款双通道可编程延迟芯片主要用于 Clock 或 Data 去偏斜和定时调整。NB6L295M 在那两个单独的可变延迟通道 PD0 和 PD1 可以在以下之一中配置两种操…

基于PiAlert的网络扫描器NetAlertX

什么是 NetAlertX ? NetAlertX 是💻🔍 WIFI/LAN 入侵检测器。能扫描连接到您的网络的设备,并在发现新设备或未知设备时向您发出警报。能够在一个地方可视化您的所有网络,获得实时警报,并与您的智能家居无缝…

探秘微信传奇:背后的产品观重塑社交江湖

在当今互联网的浩瀚星空中,微信无疑是那颗最为璀璨的明星。它如同一座无形的桥梁,连接着全球数十亿人的生活、情感与梦想。那么,微信究竟是如何铸就这般传奇的呢?让我们一同深入探寻微信背后的产品观,揭开它神秘的面纱…

C练手题--Exclusive “or“ (xor) Logical Operator 【8 kyu】

一、原题 链接:Training on Exclusive "or" (xor) Logical Operator | Codewars Exclusive "or" (xor) Logical Operator Overview In some scripting languages like PHP, there exists a logical operator (e.g. &&, ||, and, or, e…

2024百元蓝牙耳机推荐有哪些?四款百元王炸机型2024推荐

2024年市场上的蓝牙耳机品牌和型号繁多,其中不乏性价比极高的选择,对于那些寻求高品质、高性价比的消费者来说,百元级别的蓝牙耳机成了最吸引人的选择,那么2024百元蓝牙耳机推荐有哪些?为了帮助消费者在2024年作出明智…

统筹1000+代理商账号,月均传播量达1200w+,互联网企业区域业务指标提升300%

五菱联动全网经销商账号促进业务增长、雅迪打造抖音万店矩阵实现流量串联带动销量、贝壳推出“银河计划”孵化上万个房产自媒体达人促进潜客转化........ 越来越多的企业开始在各大社媒平台上建设经销商矩阵、门店矩阵、代理商矩阵,让经销商、门店、代理商等这些终端…

C#上位机使用Microsoft.Office.Interop.Excel和EPPlus库对Excel或WPS表格进行写操作

C#上位机使用Microsoft.Office.Interop.Excel和EPPlus库对Excel或WPS表格进行写操作 一、使用Microsoft.Office.Interop.Excel库 1、通过NuGet包管理器添加引用 按照下图中红框所示进行操作。 需要安装Microsoft.Office.Interop.Excel包 添加Microsoft Office 16.0 Object …

搭建大型分布式服务(四十四)SpringBoot 无代码侵入实现多Kafka数据源:单分区提升至十万级消费速度!

系列文章目录 文章目录 系列文章目录前言一、本文要点二、开发环境三、原项目四、修改项目五、测试一下五、小结 前言 在过去的一段时间里,我们利用了AI大模型写了一个多线程并发框架,那么,我们怎样集成到Kafka组件里,让消费速度…

15种高级RAG技术:从预检索到生成全面提升RAG效果

检索增强生成 (RAG) 是一种强大的技术,它将信息检索与生成式 AI 相结合,以产生更准确、上下文更丰富的响应。本文将探讨 15 种高级 RAG 技术,以提高生成式 AI 系统的输出质量和整体性能的鲁棒性。这样做使本文能够测试…

基于ROP漏洞挖掘与利用

支持一对一答疑的购买网址 通常情况下栈溢出可能造成的后果有两种,一类是本地提权另一类则是远程执行任意命令,通常C/C并没有提供智能化检查用户输入是否合法的功能,同时程序编写人员在编写代码时也很难始终检查栈是否会发生溢出&#xff0c…