C#高级:C#中你不知道的值类型装箱的情况

最近在学习一些深度的关于C#的底层知识,后面分享一些C#的底层知识,感觉C#在这一方面完全不如Java那么好,生态环境还得再运营。

前言

       C#的值类型是高性能必备的,但是值类型的装箱反而适得其反,特别是对Unity这种糟糕的GC实现(Unity使用GC算法不会压缩内存,这是因为Unity底层采用的是C++,不允许对堆内存中指针进行移动),小对象的装箱导致内存容易碎片化,这也是为什么Unity用了协程,反而协程还不能大量使用,服了。只不过希望Unity早点实现向.Net Core的转移吧。

       言归正传,今天不会讲那些值类型向上转型为System.Object而导致的装箱操作,而是讲一些你没有意识到的装箱行为。

值类型什么时候会装箱?

这儿主要讲结构体这种自定义的值类型。

一、不重写Equals、GetHashCode、ToString方法

       如果自定义的值类型不重写这两个方法,一旦这个类型进行了比较操作,OK呀,调用值类型的父类ValueType的Equals方法,那么将造成大量的GC分配,因为父类的实现是基于反射的实现,特别是在Unity中反射的调用成本太大了,Unity会缓存反射对象,同时不会回收它(可以去官网看)。那么为什么不重写这三个方法会导致装箱呢?因为这三个方法是父类的,在父类的方法表中,你不重写,你的方法表中没有,就会去找父类,一旦找父类,就必须装箱,因为需要类型指针,而值类型是没有类型指针的,因此会进行装箱操作。

        这儿多讲一嘴,所有引用类型都必须有一个类型指针和同步索引块。后面再分享这些知识。即使是一个null对象都有这两个东西。

二、调用GetType()方法

       想不到吧,调用这个方法也会装箱,为什么呢?因为GetType()是顶级父对象System.Object的密封方法,原因就如前面讲的那样,GetType()方法在父类的方法表中,因此必须进行装箱。

如何更好的使用结构体

       设计结构体的目的就是为了性能,如果只是进行方法传参、功能增强等,建议使用ref struct,因为使用ref struct,编译器会保证它一定不会被装箱。如果你想验证上面讲的装箱的情况,你就会发现,如果你不重写上面的三个虚方法,你根本看不到ToString()、GetHashCode()、Equals()方法,同时不显示重置C#的运算符,任何比较编译器都会报错。如果你的结构体要被一个引用类型引用,那么一定记得重写父类的三个虚方法,能不调用GetType()就不要调用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Avalon712

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值