netcore高级知识点,内存对齐,原理与示例
最近几年一直从事物联网开发,与硬件打交道越来越多,发现越接近底层开发对性能的追求越高,毕竟硬件资源相对上层应用来实在是太缺乏了。今天想和大家一起分享关于C#中的内存对齐,希望通过理解和优化内存对齐,可以帮助大家更好的提高程序性能以及资源利用效率。
什么是内存对齐
内存对齐指把数据存储在内存中时,需要按照某种特定规则进行存储,使其内存存储在符合特定边界要求的内存地址上。而内存对齐主要目的则是减少CPU内存操作次数,提高内存操作效率,并提升CPU缓存命中率,从而提升整体性能。
内存对齐原则
内存对齐原则包含两部分:内存对齐边界和内存对齐规则。
① 内存对齐边界:数据存储在内存中的起始内存地址必须满足条件。例如,8字节对齐则要求数据的起始内存地址必须是8的倍数;
② 内存对齐规则:不同的硬件平台内存对齐规则也各有差异,比如:x86、x64架构在内存对齐方面比较宽松,而ARM、RISC-V架构则相对比较严格;一般32位处理器要求4字节对齐,而64位处理器要求8字节对齐;
因此不同的CPU架构和平台则内存对齐规则也各有不同,而这些差异也都是为了使数据在内存中的布局更加符合CPU操作方式,从而提高程序执行效率。
C#中的内存对齐
1、“托管代码”和“非托管代码”
托管代码:执行过程交给运行时CLR管理的代码,运行时CLR负责提取托管代码并编译成机器代码最后执行,同时运行时CLR还负责自动内存管理、安全边界和类型安全等重要服务。
“非托管代码”:即不被运行时CLR管理的代码,比如运行C/C++语言编写的代码,而此时开发任意就需要亲自处理很多事情,比如内存管理、垃圾回收、安全问题等等。
因此一般对于托管代码来说,内存的分配以及对齐策略都被运行时CLR一手包办了,无需我们过多关注,而如果需要通过P/Invoke和COM互操作来调用非托管代码则需要开发者自己处理内存对齐策略了。
当然也不是说纯托管代码就没有对内存对齐操作空间了,只是相对来说与非托管代码交互时使用内存对齐操作空间更大。
2、StructLayoutAttribute特性
无论托管内存还是非托管内存,都可以用StructLayoutAttribute特性来对其进行内存布局控制,简单来说对于托管代码可以使用LayoutKind枚举值Explicit进行显示控制,而对于非托管代码LayoutKind枚举值都可以控制。
示例-字段顺序影响内存占用大小
我们用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等复杂的功能都没有介绍,有兴趣的可以深入研究研究。本文只是简单内存对齐的原理原则以及简单的内存优化,后面有机会再给大家深入介绍。
netcore高级知识点,内存对齐,原理与示例的更多相关文章
- C语言内存对齐原理
一.什么是字节对齐,为什么要对齐? 现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特定的内存地址访问,这 ...
- c++内存对齐原理
转载自http://blog.csdn.net/it_yuan/article/details/24651347 #类中的元素 0. 成员变量 1. 成员函数 2. 静态成员变量 3. 静 ...
- centos7 lldb 调试netcore应用的内存泄漏和死循环示例(dump文件调试)
写个demo来玩一玩linux平台下使用lldb加载sos来调试netcore应用. 当然,在真实的产线环境中需要分析的数据和难度远远高于demo所示,所以demo的作用也仅仅只能起到介绍工具的作用. ...
- 重磅硬核 | 一文聊透对象在 JVM 中的内存布局,以及内存对齐和压缩指针的原理及应用
欢迎关注公众号:bin的技术小屋 大家好,我是bin,又到了每周我们见面的时刻了,我的公众号在1月10号那天发布了第一篇文章<从内核角度看IO模型的演变>,在这篇文章中我们通过图解的方式以 ...
- C/C++ 知识点1:内存对齐
预备知识:基本类型占用字节 在32位操作系统和64位操作系统上,基本数据类型分别占多少字节呢? 32位操作系统: char : 1 int :4 short : 2 unsigned ...
- [ASP.NET MVC 大牛之路]03 - C#高级知识点概要(2) - 线程和并发
本人博客已转移至:http://www.exblr.com/liam 我也想过跳过C#高级知识点概要直接讲MVC,但经过前思后想,还是觉得有必要讲的.我希望通过自己的经验给大家一些指引,带着大家一起 ...
- C#高级知识点概要(2) - 线程和并发
原文地址:http://www.cnblogs.com/Leo_wl/p/4192935.html 我也想过跳过C#高级知识点概要直接讲MVC,但经过前思后想,还是觉得有必要讲的.我希望通过自己的经验 ...
- 【转帖】linux内存管理原理深入理解段式页式
linux内存管理原理深入理解段式页式 https://blog.csdn.net/h674174380/article/details/75453750 其实一直没弄明白 linux 到底是 段页式 ...
- C/C++: C++位域和内存对齐问题
1. 位域: 1. 在C中,位域可以写成这样(注:位域的数据类型一律用无符号的,纪律性). struct bitmap { unsigned a : ; unsigned b : ; unsigned ...
- [ASP.NET MVC 大牛之路]02 - C#高级知识点概要(1) - 委托和事件
在ASP.NET MVC 小牛之路系列中,前面用了一篇文章提了一下C#的一些知识点.照此,ASP.NET MVC 大牛之路系列也先给大家普及一下C#.NET中的高级知识点.每个知识点不太会过于详细,但 ...
随机推荐
- yb课堂 ECMAScript 6常见语法快速入门 《三十一》
什么是ES 6 ECMAScript 6(简称ES6)是于2015年6月正式发布的JavaScript语言的标准,正式名为ECMAScript 2015(ES2015).它的目标是使用JavaScri ...
- SwiftUI学习01-基本使用
SwiftUI 是苹果推出的一种现代化方式,用于创建跨所有 Apple 平台的用户界面.它通过声明性语法简化了 UI 的开发流程.下面是一个基本的 SwiftUI 示例,展示了如何使用 SwiftUI ...
- oeasy教您玩转vim - 32 - # 函数跳转
程序移动 回忆上节课内容 上次内容很简单,主要针对文本类素材 移动段落 {向前 }向后 移动句子 (向前 )向后 如果我想程序中快速移动 怎么办? #首先下载文本找到tomsawyer.txt g ...
- .NET科普:.NET简史、.NET Standard以及C#和.NET Framework之间的关系
最近在不少自媒体上看到有关.NET与C#的资讯与评价,感觉大家对.NET与C#还是不太了解,尤其是对2016年6月发布的跨平台.NET Core 1.0,更是知之甚少.在考虑一番之后,还是决定写点东西 ...
- Day 5 - 双指针与折半搜索
双指针 本页面将简要介绍双指针. 引入 双指针是一种简单而又灵活的技巧和思想,单独使用可以轻松解决一些特定问题,和其他算法结合也能发挥多样的用处. 双指针顾名思义,就是同时使用两个指针,在序列.链表结 ...
- Web开发中【密码加密】详解
作为一名Web开发人员,我们经常需要与用户的帐号系统打交道,而这其中最大的挑战就是如何保护用户的密码.经常会看到用户账户数据库频繁被黑,所以我们必须采取一些措施来保护用户密码,以免导致不必要的数据泄露 ...
- C# 泛型单例工厂
核心代码,线程安全 class SingletonFactory<T> where T : new() { private static T uniqueInstance; private ...
- Git 克隆仓库报unable to get local issuer certificate错误解决方法
Git 克隆仓库报unable to get local issuer certificate错误解决方法 By:授客 QQ:1033553122 问题描述 克隆gitlab上的仓库,报错,如下 $ ...
- 【杂谈】JPA乐观锁改悲观锁遇到的一些问题与思考
背景 接过一个外包的项目,该项目使用JPA作为ORM. 项目中有多个entity带有@version字段 当并发高的时候经常报乐观锁错误OptimisticLocingFailureException ...
- 【BatchProgram】工作用的小工具 - 自动访问常用页面
需求: 我需要打开很多页面,但是忘了收藏的话,每次都要重新去找一遍打开 页面很多,不是一两个了,为什么这么多?因为开发情况就是这样啊: 正式生产一个页面,UAT测试一个页面,本地调试一个页面 每日工作 ...