1.sizeof的作用

我集体的了解:sizeof是用来获取非托管类型所占内存大小的操作符。

微软官网对sizeof的定义:

sizeof 运算符返回给定类型的变量所占用的字节数。 sizeof 运算符的参数必须是一个sizeof的名称,或是一个限定为非托管类型的类型参数。

《微软官网文档》
https://docs.microsoft.com/zh...

2.sizeof和Mashal.sizeof

首先要说的是sizeof和Marshal.SizeOf是有差别的。

C# 中的sizeof和Marshal.SizeOf都能够用来获取非托管类型的大小,然而性能上有差异,后果也略有差别。

sizeof在失常环境下只能用于预约义的非托管类型,如int、long等等。在unsafe环境下,sizeof能够被用于值类型,然而值类型中不能够有援用类型,否则C#编译器会报错。

Marshal.SizeOf则是取得该类型被Marshal(转换,通常翻译为列集,指数据从一种类型转换到另外一种类型)到对应的非托管类型的大小。和sizeof不同,Marshal.SizeOf容许用在含有援用类型的值类型上。

参考资料:《Marshal.SizeOf和sizeof的区别》

先看输入后果:

public struct Struct1 {    public int Id;}public struct Struct2 {    public int Id;    public string Name;}// sizeof()测试 零碎内置的根本类型sizeof是固定常量值,编译器主动替换,不是通过计算失去的 不须要用unsafe 自定义的须要unsafe下计算private void SizeofTest() {    Console.WriteLine(sizeof(bool));   // 1    Console.WriteLine(sizeof(byte));   // 1    Console.WriteLine(sizeof(sbyte));  // 1    Console.WriteLine(sizeof(short));  // 2    Console.WriteLine(sizeof(ushort)); // 2    Console.WriteLine(sizeof(int));    // 4    Console.WriteLine(sizeof(uint));   // 4    Console.WriteLine(sizeof(long));   // 8    Console.WriteLine(sizeof(ulong));  // 8    Console.WriteLine(sizeof(char));   // 2    Console.WriteLine(sizeof(float));  // 4    Console.WriteLine(sizeof(double)); // 8    //自定义struct    unsafe {        Console.WriteLine(sizeof(Struct1));// 4        //Console.WriteLine(sizeof(Struct2));// 编译器报错 无奈获取托管类型("Struct2")的地址和大小,或者申明指向他的指针    }}// Mashal.SizeOf()测试private void MarshalSizeofTest() {    // using System.Runtime.InteropServices;    Console.WriteLine(Marshal.SizeOf(typeof(bool)));   // 4 (sizeof是1)    Console.WriteLine(Marshal.SizeOf(typeof(byte)));   // 1    Console.WriteLine(Marshal.SizeOf(typeof(sbyte)));  // 1    Console.WriteLine(Marshal.SizeOf(typeof(short)));  // 2    Console.WriteLine(Marshal.SizeOf(typeof(ushort))); // 2    Console.WriteLine(Marshal.SizeOf(typeof(int)));    // 4    Console.WriteLine(Marshal.SizeOf(typeof(uint)));   // 4    Console.WriteLine(Marshal.SizeOf(typeof(long)));   // 8    Console.WriteLine(Marshal.SizeOf(typeof(ulong)));  // 8    Console.WriteLine(Marshal.SizeOf(typeof(char)));   // 1 (sizeof是2)    Console.WriteLine(Marshal.SizeOf(typeof(float)));  // 4    Console.WriteLine(Marshal.SizeOf(typeof(double))); // 8    // 自定义struct    Console.WriteLine(Marshal.SizeOf(typeof(Struct1)));// 4    Console.WriteLine(Marshal.SizeOf(typeof(Struct2)));// 8} 

3.sizeof大小的计算

在计算之前,请看下面SizeofTest()办法内的输入后果,记住根本数据类型的大小,用来计算。

我集体依据输入后果总结了以下几个计算规定:

1.首先确定最小调配空间UnitSize

32位利用每一个单位调配的最大空间为32位即8字节。

找到struct成员中根本数据类型size最大的值,单元的size值在该maxSize值和8之间取最小。(int unitSize = Math.Min(maxSize, 8))

2.先调配一个单元空间, 从上往下按程序装struct中的成员size。

3.每个类型占用空间的起始序号必须为0或该类型size的整数倍,空间不够就从新开一个单位空间。

比方:

bool占1字节,占用空间的起始序号能够为0,1,2,3,4...。

short占2字节,占用空间的起始序号能够为0,2,4 ....。

int占4字节,占用空间的起始序号能够为0,4....。

4.如果某个成员是自定义的值类型, maxSize须要遍历值类型成员中的根本数据类型size决定,不是由值类型的总size决定。

大略计算过程如下:

// 原文地址:https://www.cnblogs.com/zhangyukof/p/16159965.htmlpublic struct Struct3 {    public bool a;    public int b;    public short c;}// 以计算struct3 size为例:// 1.先获取struct中 成员数据类型size最大的int maxSize = 4; // bool = 1, int = 4, short = 2// 2.单元空间大小取成员类型size和8之间的最小值int unitSize = Math.Min(maxSize, 8); // 4// 3.开始计算占用空间(1) □ □ □ □   // 调配一个新单元 4字节(2) ■ □ □ □   // 装入bool 占用一个字节(3) ■ □ □ □   // 残余空间序号不满足0或4的整数倍 不能装入int 重新分配一个单元    □ □ □ □(4) ■ □ □ □   // 装入int 从新单元的0地位开始占用4个字节    ■ ■ ■ ■(5) ■ □ □ □   // 调配一个新单元 4字节    ■ ■ ■ ■    □ □ □ □(6) ■ □ □ □   // 装入short 占用2个字节    ■ ■ ■ ■    ■ ■ □ □// 4.共计3个单元 3*unitSize = 12字节

4.成员程序影响sizeof的大小

因为调配的规定3是每个类型占用空间的起始序号必须为0或该类型size的整数倍,空间不够就从新开一个单位空间。

重新分配一个新的单元从0地位开始装,所以成员的程序有可能影响sizeof的大小。

比方把struct3中 b和c的程序调换一下就变成了8字节

public struct Struct3 {    public bool a;    public short c;    public int b;}(1) □ □ □ □   // 调配一个新单元 4字节(2) ■ □ □ □   // 装入bool 占用一个字节(3) ■ □ ■ ■   // 装入short 占用2个字节 (short起始序号为2)(4) ■ □ ■ ■   // 调配一个新单元 4字节    □ □ □ □(5) ■ □ ■ ■   // 装入int 占用4个字节    ■ ■ ■ ■// 共计2个单元 2*unitSize = 8字节

没错,这是一个口试考点。

5.自定义值类型影响sizeof的大小

再来一个难一点的,当有成员类型是自定义类型 并且总size超过8 看看后果如何:

计算自定义值类型Struct4 size大小:

public struct Struct4 {    public bool a;    // size = 1    public StructSize16 b;    // size = 16    public int c;     // size = 4    public short d;   // size = 2}public struct StructSize16 {    public int a1; // size = 4    public int a2;    public int a3;    public int a4;}

如果依照以下形式计算:

int maxSize = 16; // StructSize16 = 16int unitSize = Math.Min(maxSize, 8); // 81.■ □ □ □ □ □ □ □// 调配一个单元8字节 装入bool 占1字节2.■ □ □ □ □ □ □ □ // 残余空间的起始序号不满足StructSize16的需要 调配2个新单元 装入StructSize16 占16个字节  ■ ■ ■ ■ ■ ■ ■ ■  ■ ■ ■ ■ ■ ■ ■ ■  3.■ □ □ □ □ □ □ □ // 调配一个单元8字节 装入int 占4字节  ■ ■ ■ ■ ■ ■ ■ ■  ■ ■ ■ ■ ■ ■ ■ ■  ■ ■ ■ ■ □ □ □ □  4.■ □ □ □ □ □ □ □ // 装入short 占2字节  ■ ■ ■ ■ ■ ■ ■ ■  ■ ■ ■ ■ ■ ■ ■ ■  ■ ■ ■ ■ ■ ■ □ □  5.共计4个单位空间  4*unitSize = 32字节

后果就错了,因为成员遇到自定义类型要遍历自定义类型里的根本数据类型再确定maxSize

自定义值类型外面的成员有4个 都是int型 maxSize为4,这里要留神以下,正确计算形式应该如下:

int maxSize = 4; // bool = 1, short = 2, int = 4int unitSize = Math.Min(maxSize, 8); // 41.■ □ □ □ // 调配一个单元4字节 装入bool 占1字节2.■ □ □ □ // 残余3字节的空间装不下StructSize16 调配4个新单元 装入StructSize16 占16个字节  ■ ■ ■ ■  ■ ■ ■ ■  ■ ■ ■ ■  ■ ■ ■ ■  3.■ □ □ □ // 调配一个新单元4字节 装入int 占4字节  ■ ■ ■ ■  ■ ■ ■ ■  ■ ■ ■ ■  ■ ■ ■ ■  ■ ■ ■ ■4.■ □ □ □ // 调配一个新单元4字节 装入short 占2字节  ■ ■ ■ ■  ■ ■ ■ ■  ■ ■ ■ ■  ■ ■ ■ ■  ■ ■ ■ ■  ■ ■ □ □  5.共计7个单位空间  7*unitSize = 28字节

这个计算结果与输入后果保持一致,都是28字节。

把自定义类型StructSize16换成decimal后果也是28字节,因为decimal外面也有4个int类型的成员,从后果看来,decimal没有被当成根本数据类型来对待,maxSize是4不是16。

最初再定义一个略微简单点的类型来测验一下计算规定是否正确:

public struct Student {    public int num;    public bool isAtSchool;    public short age;    public long id;    public byte rank;}int maxSize = 8; // bool = 1, byte = 1, short = 2, int = 4, long = 8int unitSize = Math.Min(maxSize, 8); // 81.□ □ □ □ □ □ □ □ // 调配一个单元8字节2.■ ■ ■ ■ □ □ □ □ // 装入int 占4字节3.■ ■ ■ ■ ■ □ □ □ // 装入bool 占1字节4.■ ■ ■ ■ ■ □ ■ ■ // 装入short 占2字节 起始序号为65.■ ■ ■ ■ ■ □ ■ ■ // 调配一个新单位8字节  □ □ □ □ □ □ □ □  6.■ ■ ■ ■ ■ □ ■ ■ // 装入long 占8字节  ■ ■ ■ ■ ■ ■ ■ ■  7.■ ■ ■ ■ ■ □ ■ ■ // 新调配一个单位空间8字节  ■ ■ ■ ■ ■ ■ ■ ■  □ □ □ □ □ □ □ □  8.■ ■ ■ ■ ■ □ ■ ■ // 装入byte 占1字节  ■ ■ ■ ■ ■ ■ ■ ■  ■ □ □ □ □ □ □ □  9.共计 3*8 = 24字节 // 计算结果与输入后果统一 都是24字节 计算正确// 能够看到空间第三行首位独自占了一个字节,空余7个字节,// 如果把第三行的数据挪动到第一行空白的地位,那么就不须要第三行了,能够节俭空间,试一下。// 把Student中rank字段的地位挪动到isAtSchool前面。public struct Student {    public int num;    public bool isAtSchool;    public byte rank;    public short age;    public long id;}// 这样内存占用就变成了:■ ■ ■ ■ ■ ■ ■ ■■ ■ ■ ■ ■ ■ ■ ■// 实践上应该16个字节就够用了,运行测试代码输入一下后果,sizeof(Student)的确是16,测验胜利。

总结:

sizeof()计算非托管类型的大小不是间接依照成员数据类型大小加起来的,波及到一些非凡的计算规定,失常应用不须要记这些简单的货色。

如果须要用到这部分常识了,应该波及到性能优化或遇到考题了,记住根本数据类型的size就能够满足个别需要了。

struct内成员的程序会影响sizeof大小 成员变量也会影响sizeof大小。没必要的变量不要定义为成员变量,private也会被计算进size内,成员尽量用数值size更小的定义。

最初再附赠一个查看自定义struct内存排布的办法:

我用的是Visual Studio软件,关上调试 > 窗口 > 内存 > 内存1。

断点设置在申明对象的地位,在中断的时候内存地址栏输出&对象名称。

给对象的成员一一赋值成最大值,F10往下走就能够看到内存变动了。

至此,sizeof的计算过程告一段落。

PS:转载请表明原文地址:https://www.cnblogs.com/zhang...

参考资料:

《C# Marshal.SizeOf和sizeof的区别》
《C#sizeof用法》