500w 的引用类型和值类型到底有多大差异?

大家在写代码的时候,相信有很多朋友对 struct 认知不是很足,导致能用 class 的地方绝对不用struct,但大家有没有发现,最近的几个 C# 版本中,底层框架中有很多 class 的替代品,比如说:

  1. Task 和 ValueTask

  2. Tuple 和 ValueTuple。

本质上来说都是为了提少 GC 负担,提高程序性能。

今天就和大家简单聊下,struct 和 class 到底在内存占用上有多大差距,首先我们分别定义两个空类型,然后分别灌入 500w

class Program{static void Main(string[] args){var list = new List<Test>(5000000);var valueList = new List<ValueTest>(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.List`1[[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.List`1[[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.List`1[[ConsoleApp6.Test, ConsoleApp6]])
0:000> !objsize 000000000281b698
sizeof(000000000281B698) = 5000056 (0x4c4b78) bytes (System.Collections.Generic.List`1[[ConsoleApp6.ValueTest, ConsoleApp6]])

从输出中可以看到,list=160M,而 valuelist=5M 居然相差 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
00000000`14e36a70  00007ffb`2b596c60 00000000`004c4b40
00000000`14e36a80  00000000`00000000 00000000`00000000
00000000`14e36a90  00000000`00000000 00000000`00000000
00000000`14e36aa0  00000000`00000000 00000000`00000000
00000000`14e36ab0  00000000`00000000 00000000`00000000
00000000`14e36ac0  00000000`00000000 00000000`00000000
00000000`14e36ad0  00000000`00000000 00000000`00000000
00000000`14e36ae0  00000000`00000000 00000000`00000000

从输出看,对于一个空 struct 而言在内存中只占用了 1byte

接下来看一下 引用类型,用 dp 0000000012811038 即可。

0:000> dp 0000000012811038
00000000`12811038  00007ffb`2b596a80 00000000`004c4b40
00000000`12811048  00000000`028110e8 00000000`02811100
00000000`12811058  00000000`02811118 00000000`02811130
00000000`12811068  00000000`02811148 00000000`02811160
00000000`12811078  00000000`02811178 00000000`02812500
00000000`12811088  00000000`028128a8 00000000`028128c0
00000000`12811098  00000000`028128d8 00000000`028128f0
00000000`128110a8  00000000`02812908 00000000`028129e8

刚才也提到了两者相差32倍,也就是一个引用类型应该要占用 32byte才对,是吧,那这个是怎么算的呢?首先在 64bit 平台引用类型的最小size=3*8=24byte, 也即 **(对象头+方法表指针+空占位符)**, 这个 sizecoreclr 中也是有 const 声明的, 剩下的 8byte 就是上面用 dp 命令看到的数组中的每一元素的 方法表指针 啦。

至此,大家都明白了吧。

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

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

相关文章

list对象排序

在数据库中查出来的列表list中&#xff0c;往往需要对不同的字段重新排序&#xff0c;一般的做法都是使用排序的字段&#xff0c;重新到数据库中查询。如果不到数据库查询&#xff0c;直接在第一次查出来的list中排序&#xff0c;无疑会提高系统的性能。 只要把第一次查出来的结…

【转】HTML5移动端最新兼容问题解决方案

1、安卓浏览器看背景图片&#xff0c;有些设备会模糊。 用同等比例的图片在PC机上很清楚&#xff0c;但是手机上很模糊&#xff0c;原因是什么呢&#xff1f;经过研究&#xff0c;是devicePixelRatio作怪&#xff0c;因为手机分辨率太小&#xff0c;如果按照分辨率来显示网页&a…

一天不编程,脑子比猪笨

一天不编程&#xff0c;脑子比猪笨&#xff1b;一周不编程&#xff0c;爪爪变猪蹄。

hibernate注解方式来处理映射关系

在hibernate中&#xff0c;通常配置对象关系映射关系有两种&#xff0c;一种是基于xml的方式&#xff0c;另一种是基于annotation的注解方式&#xff0c;熟话说&#xff0c;萝卜青菜&#xff0c;可有所爱&#xff0c;每个人都有自己喜欢的配置方式&#xff0c;我在试了这两种方…

linux之vim复制多行、光标跳转到指定行、插入当前光标上和下行

1、复制多行 number yy 2、光标跳转到指定行 :line 3、插入当前光标到上行 O 4、插入当前光标到下行 o

提的最多的数据库“索引”,先来简单了解一下

前言现在的项目对于数据库操作基本上都是使用封装好的ORM框架&#xff0c;这样开发效率相对来说有所提高。但由于框架的封装&#xff0c;会自动生成SQL语句&#xff0c;这让一些小伙伴对SQL产生了一种陌生感(基本不写SQL)&#xff0c;导致排查业务执行缓慢问题时比较盲目&#…

【个人阅读】软件工程M1/M2阶段总结

这次作业是好久以前布置的&#xff0c;由于学期末课程设计任务比较重&#xff0c;我在完善M2阶段的代码的同时又忙于数据库的实现和编译器的实现&#xff0c;一度感觉忙得透不过气来。。。。到这些都基本完成的时候&#xff0c;会看自己以前的阅读心得&#xff0c;觉得经过了M1…

Excel实用函数大全(名称、功能、说明、用法、举例)

我们在使用Excel制作表格整理数据的时候,常常要用到它的函数功能来自动统计处理表格中的数据。这里整理了Excel中使用频率最高的函数的功能、使用方法,以及这些函数在实际应用中的实例剖析,并配有详细的介绍。 1、ABS函数    函数名称:ABS    主要功能:求出相应数字…

DB2 SQL 递归实现多行合并

最终效果 原始数据&#xff1a; 转换脚本&#xff1a; WITH post_a AS ( SELECT DISTINCT T.EMP_NO,S.CODE_ FROM inscndb.DTFMA000_EMP_POST T ,VIEW_BI_POST S WHERE T.POST||-||POST2 S.POST ), post_b AS (SELECT emp_no,code_,ROW_NUMBER() OVER(PARTITION BY EMP_NO ORD…

C++之greater和less

1、greater、 less 他在头文件<functional>里面, greater和less都重载了操作符 定义如下: // TEMPLATE STRUCT greater template<class _Ty> struct greater : public binary_function<_Ty, _Ty, bool> { // functor for operator>bool operator()(cons…

mysql逻辑结构设计_数据库设计:逻辑结构设计

概念结构设计所得的E-R模型是对用户需求的一种抽象的表达形式&#xff0c;它独立于任何一种具体的数据模型&#xff0c;因而也不能为任何一个具体的DBMS所支持。为了能够建立起最终的物理系统&#xff0c;还需要将概念结构进一步转化为某一DBMS所支持的数据模型&#xff0c;然后…

.NET6之MiniAPI(二十五):Dapper

注&#xff1a;如果你使用Dapper一段时间了&#xff0c;这篇你可以跳过去了。在第十二篇中&#xff0c;我们聊过官方的ORM——EntityFramework&#xff0c;它可以把SQL细节都隐藏&#xff0c;这对于一些标准化的关系数据库项目非常便捷。今天&#xff0c;介绍另外一个流行的ORM…

移动端web开发整理

/* 移动端定义字体的代码 */body {   font-family: "Helvetica Neue", Helvetica; } ios端触摸时&#xff0c;会出现一个半透明灰色遮罩  如果想要禁用&#xff0c;可设置-webkit-tap-highlight-color的alpha值为0 body{-webkit-tap-highlight-color: rgba(0,0,…

LeetCode Implement Queue using Stacks (数据结构)

题意&#xff1a; 用栈来实现队列。 思路&#xff1a; 一个栈是不够的&#xff0c;至少要两个。 &#xff08;1&#xff09;插入。永远只插入到stack1中&#xff08;插到栈顶&#xff09;。 &#xff08;2&#xff09;弹出。如果stack2不为空&#xff0c;直接弹出stack2的栈顶&…

C++之STL之priority_queue

1、priority_queue介绍 priority_queue 是优先队列 模板声明带有三个参数,priority_queue<Type, Container, Functional> Type为数据类型,Container为保存数据的容器,Functional为元素比较方式 Container必须是用数组实现的容器,如 vector, deque不能用list, STL里面…

直角三角形知道两边求角度_每日一讲:解直角三角形(3.21)

考点一、直角三角形的性质 1、直角三角形的两个锐角互余&#xff1a;可表示如下&#xff1a;∠C90∠A∠B902、在直角三角形中&#xff0c;30角所对的直角边等于斜边的一半。3、直角三角形斜边上的中线等于斜边的一半4、勾股定理&#xff1a; 如果直角三角形的两直角边长分别为…

用VBA得到EXCEL表格中的行数和列数

用VBA得到EXCEL表格中的行数和列数 每种方法中上面的是Excel的行数&#xff0c;下面的是Excel的列数。 方法1: ActiveSheet.UsedRange.Rows.Count ActiveSheet.UsedRange.Columns.Count 缺点&#xff1a;有时可能会比实际数大一些&#xff0c;原因是如果你把最后几行&#xff0…

Javascript屏蔽鼠标的右键的两种方法。

方法一&#xff1a;利用鼠标button的键值 <script language"javascript">function blockright(oEvent) {var oDiv document.getElementById("display");if (window.event) oEvent window.event; //处理兼容性&#xff0c;获得事件对象if (oEvent.b…

Blazor University (4)组件 — 单向绑定

原文链接&#xff1a;https://blazor-university.com/components/one-way-binding/单向绑定源代码[1]此时我们在页面内显示了一个组件&#xff0c;但内容是静态的。我们真正想要的是能够动态输出内容。如果我们更改 /Components/MyFirstComponent.razor 的内容&#xff0c;我们…

Java Web项目开发流程

2019独角兽企业重金招聘Python工程师标准>>> 1.Web项目开发流程图解 2.Web项目开发的细节&#xff08;转载&#xff09; 任何一个项目或者系统开发之前都需要定制一个开发约定和规则&#xff0c;这样有利于项目的整体风格统一、代码维护和扩展。由于Web项目开发的分…