素材网站推广方案,网站自然排名怎么优化,高端网站有哪些优势,长春网站建设技术托管大家在写代码的时候#xff0c;相信有很多朋友对 struct 认知不是很足#xff0c;导致能用 class 的地方绝对不用struct#xff0c;但大家有没有发现#xff0c;最近的几个 C# 版本中#xff0c;底层框架中有很多 class 的替代品#xff0c;比如说#xff1a;Task 和 Va… 大家在写代码的时候相信有很多朋友对 struct 认知不是很足导致能用 class 的地方绝对不用struct但大家有没有发现最近的几个 C# 版本中底层框架中有很多 class 的替代品比如说Task 和 ValueTaskTuple 和 ValueTuple。本质上来说都是为了提少 GC 负担提高程序性能。今天就和大家简单聊下struct 和 class 到底在内存占用上有多大差距首先我们分别定义两个空类型然后分别灌入 500w 。class Program{static void Main(string[] args){var list new ListTest(5000000);var valueList new ListValueTest(5000000);for (int i 0; i 5000000; i){list.Add(new Test());valueList.Add(new ValueTest());}Console.WriteLine(结束);Console.ReadLine();}}class Test{}struct ValueTest{}接下来用 windbg 看一下差异。0:000 !clrstack -a
OS Thread Id: 0x4040 (0)Child SP IP Call Site
00000000001CE920 00007ffb8fb147bc System.Console.ReadLine() [/_/src/libraries/System.Console/src/System/Console.cs 629]
00000000001CE950 00007ffb2b4c621b ConsoleApp6.Program.Main(System.String[]) [D:\net5\ConsoleApp1\ConsoleApp6\Program.cs 24]PARAMETERS:args (0x00000000001CE9D0) 0x000000000281a650LOCALS:0x00000000001CE9B8 0x000000000281b6780x00000000001CE9B0 0x000000000281b6980x00000000001CE9AC 0x00000000004c4b400x00000000001CE9A0 0x00000000000000000x00000000001CE99C 0x00000000000000000:000 !DumpObj /d 000000000281b678
Name: System.Collections.Generic.List1[[ConsoleApp6.Test, ConsoleApp6]]
MethodTable: 00007ffb2b594240
EEClass: 00007ffb2b57f0b0
Size: 32(0x20) bytes
File: C:\Program Files\dotnet\shared\Microsoft.NETCore.App\5.0.13\System.Private.CoreLib.dll
Fields:MT Field Offset Type VT Attr Value Name
00007ffb2b597638 4001d3c 8 System.__Canon[] 0 instance 0000000012811038 _items
00007ffb2b48b258 4001d3d 10 System.Int32 1 instance 5000000 _size
00007ffb2b48b258 4001d3e 14 System.Int32 1 instance 5000000 _version
00007ffb2b597638 4001d3f 8 System.__Canon[] 0 static dynamic statics NYI s_emptyArray
0:000 !DumpObj /d 000000000281b698
Name: System.Collections.Generic.List1[[ConsoleApp6.ValueTest, ConsoleApp6]]
MethodTable: 00007ffb2b594de8
EEClass: 00007ffb2b5a5ea0
Size: 32(0x20) bytes
File: C:\Program Files\dotnet\shared\Microsoft.NETCore.App\5.0.13\System.Private.CoreLib.dll
Fields:MT Field Offset Type VT Attr Value Name
00007ffb2b596c60 4001d3c 8 ...eApp6.ValueTest[] 0 instance 0000000014e36a70 _items
00007ffb2b48b258 4001d3d 10 System.Int32 1 instance 5000000 _size
00007ffb2b48b258 4001d3e 14 System.Int32 1 instance 5000000 _version
00007ffb2b596c60 4001d3f 8 ...eApp6.ValueTest[] 0 static dynamic statics NYI s_emptyArray
0:000 !objsize 000000000281b678
sizeof(000000000281B678) 160000056 (0x9896838) bytes (System.Collections.Generic.List1[[ConsoleApp6.Test, ConsoleApp6]])
0:000 !objsize 000000000281b698
sizeof(000000000281B698) 5000056 (0x4c4b78) bytes (System.Collections.Generic.List1[[ConsoleApp6.ValueTest, ConsoleApp6]])从输出中可以看到list160M而 valuelist5M 居然相差 32 倍 这种量级的差异在高性能的场景下足以让我们充分考量了对吧我相信有很多朋友应该能搞明白为什么会是 32 倍。真有不明白的同学我再来分析一波吧。先看struct用 dp 0000000014e36a70 看内存地址。0:000 !da 0000000014e36a70
Name: ConsoleApp6.ValueTest[]
MethodTable: 00007ffb2b596c60
EEClass: 00007ffb2b596be0
Size: 5000024(0x4c4b58) bytes
Array: Rank 1, Number of elements 5000000, Type VALUETYPE
Element Methodtable: 00007ffb2b594760
[0] 0000000014e36a80
[1] 0000000014e36a81
[2] 0000000014e36a82
[3] 0000000014e36a83
[4] 0000000014e36a84
[5] 0000000014e36a85
[6] 0000000014e36a86
[7] 0000000014e36a87
[8] 0000000014e36a88
[9] 0000000014e36a89
[10] 0000000014e36a8a
[11] 0000000014e36a8b
[12] 0000000014e36a8c
[13] 0000000014e36a8d
[14] 0000000014e36a8e
[15] 0000000014e36a8f
[16] 0000000014e36a90
...0:000 dp 0000000014e36a70
0000000014e36a70 00007ffb2b596c60 00000000004c4b40
0000000014e36a80 0000000000000000 0000000000000000
0000000014e36a90 0000000000000000 0000000000000000
0000000014e36aa0 0000000000000000 0000000000000000
0000000014e36ab0 0000000000000000 0000000000000000
0000000014e36ac0 0000000000000000 0000000000000000
0000000014e36ad0 0000000000000000 0000000000000000
0000000014e36ae0 0000000000000000 0000000000000000从输出看对于一个空 struct 而言在内存中只占用了 1byte。接下来看一下 引用类型用 dp 0000000012811038 即可。0:000 dp 0000000012811038
0000000012811038 00007ffb2b596a80 00000000004c4b40
0000000012811048 00000000028110e8 0000000002811100
0000000012811058 0000000002811118 0000000002811130
0000000012811068 0000000002811148 0000000002811160
0000000012811078 0000000002811178 0000000002812500
0000000012811088 00000000028128a8 00000000028128c0
0000000012811098 00000000028128d8 00000000028128f0
00000000128110a8 0000000002812908 00000000028129e8刚才也提到了两者相差32倍也就是一个引用类型应该要占用 32byte才对是吧那这个是怎么算的呢首先在 64bit 平台引用类型的最小size3*824byte 也即 **(对象头方法表指针空占位符)** 这个 size 在 coreclr 中也是有 const 声明的 剩下的 8byte 就是上面用 dp 命令看到的数组中的每一元素的 方法表指针 啦。至此大家都明白了吧。