范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

为什么要把类设置成密封?

  前几天笔者提交了关于FasterKvCache的性能优化代码,其中有一个点就是我把一些后续不需要继承的类设置为了sealed密封类,然后就有小伙伴在问,为啥这个地方需要设置成sealed?
  提交的代码如下所示:
  一般业务开发的同学可能接触密封类比较少,密封类除了框架设计约束(不能被继承)以外,还有一个微小的性能提升,不过虽然它是一个微小的优化点,多框架开发的作者都会做这样的优化,如果方法调用的频次很高,那也会带来很大的收益。
  笔者最开始是从.NET runtime 中的代码学习到这一个优化技巧,后面有看到meziantou大佬的文章performance-benefits-of-sealed-class[1]完整的学习了一下。
  然后本来是想翻译一下这篇文章,找了下发现 Weihan 大佬今年年初翻译了meziantou大佬的文章,质量非常高的中文版,大家可以戳链接看看,既然如此在本文中带大家回顾一下文章中例子,另外从 JIT ASM 的层面分析为什么性能会有提升。性能优势虚方法调用
  在上面提到的文章例子中,有一个虚方法的调用,大家其实要明白一点,现在面向对象的封装、继承、多态中的多态实现主要就是靠虚方法。
  一个类型可能会有子类,子类可能会重写类型的方法从而达到不同的行为(多态),而这些重写的方法都在虚方法表里,调用的话就需要查表。
  回到文中的代码,大佬构建了一个这样的测试用例:
  public class SealedBenchmark
  {
  readonly NonSealedType nonSealedType = new();
  readonly SealedType sealedType = new();
  [Benchmark(Baseline = true)]
  public void NonSealed()
  {
  // JIT不能知道nonSealedType的实际类型.
  // 它可能已经被另一个方法设置为派生类。
  // 所以,为了安全起见,它必须使用一个虚拟调用。
  nonSealedType.Method();
  }
  [Benchmark]
  public void Sealed()
  {
  // JIT确信sealedType是一个SealedType。 由于该类是密封的。
  // 它不可能是一个派生类型的实例。
  // 所以它可以使用直接调用,这样会更快。
  sealedType.Method();
  }
  }
  // 基类
  internal class BaseType
  {
  public virtual void Method() { }
  }
  // 非密封的派生类
  internal class NonSealedType : BaseType
  {
  public override void Method() { }
  }
  // 密封的派生类
  internal sealed class SealedType : BaseType
  {
  public override void Method() { }
  }
  取得的结果就是密封类要比非密封的快 98%。
  那么为什么会这样呢?首先我们来比较一下两个方法的 IL 代码,发现是一模一样的,对于方法调用都是用了callvirt(它就是用来调用虚方法的,想了解更多详情可以看这里[2]),因为 instance 是从字段中加载的,编译器无法知道具体的类型,只能使用callvirt。
  那区别在哪里呢?我们可以看到 JIT 生成后的汇编代码,可以很清楚的看到密封类少了两条指令,因为 JIT 可以从密封类中知道它不可能被继承,也不可能被重写,所以是直接跳转到密封类目标方法执行,而非密封类还有一个查表的过程。而现在很多大佬聊天说 JIT 的"去虚拟化"其实主要就是在 JIT 编译时去除了callvirt调用。
  另外文中也提到了一段代码,如果 JIT 能确定类型,也是直接调用的:
  void NonSealed()
  {
  var instance = new NonSealedType();
  instance.Method(); // JIT知道`instance`是NonSealedType,因为它是在方法中被创建的,
  // 从未被修改过,所以它使用直接调用
  }
  void Sealed()
  {
  var instance = new SealedType();
  instance.Method(); // JIT知道类型是SealedType, 所以直接调用
  }
  此时两者的汇编代码没有任何区别,都是直接 jmp 到目标方法。
  发现一个有趣的东西,如果我们切到.NET Framework 的 JIT,可以发现.NET Framework 的 JIT 没有.NET 生成的这么高效,没有直接 jmp 到目标方法,而是多了一层 call 和 ret。所以,朋友们还等什么呢?快升级.NET 版本吧。对象类型转换 (is / as)
  同样有下面这样一段代码,测试密封类和非密封类的对象类型转换性能:
  public class SealedBenchmark
  {
  readonly BaseType baseType = new();
  [Benchmark(Baseline = true)]
  public bool Is_Sealed() => baseType is SealedType;
  [Benchmark]
  public bool Is_NonSealed() => baseType is NonSealedType;
  }
  internal class BaseType {}
  internal class NonSealedType : BaseType {}
  internal sealed class SealedType : BaseType {}
  毫无疑问,密封类快 91%。
  IL 层面,两个方法都是一模一样:
  可以看到密封类的代码相当高效,直接比较一下就转换类型返回了,而非密封类还需要 call 方法走查表流程:数组
  .NET 的数组是协变的,协变兼容的话就意味着在添加进入数组时需要检查它的类型,而如果是密封类那就可以删除检查,同样有下面一段代码:
  public class SealedBenchmark
  {
  SealedType[] sealedTypeArray = new SealedType[100];
  NonSealedType[] nonSealedTypeArray = new NonSealedType[100];
  [Benchmark(Baseline = true)]
  public void NonSealed()
  {
  nonSealedTypeArray[0] = new NonSealedType();
  }
  [Benchmark]
  public void Sealed()
  {
  sealedTypeArray[0] = new SealedType();
  }
  }
  internal class BaseType { }
  internal class NonSealedType : BaseType { }
  internal sealed class SealedType : BaseType { }
  密封类的性能要高 14%左右。
  打开 IL 代码,两者编译出的方法都是一样的,但是跳转到汇编代码可以发现差别,同样的是Stelem.Ref给数组赋值,密封类只是检查了一下数组长度,然后直接赋值,而非密封类还需要调用System.Runtime.CompilerServices.CastHelpers.StelemRef进行检查才能完成赋值。将数组转换为Span
  和数组一样,将数组转换为Span时也需要插入类型检查,有如下测试代码:
  public class SealedBenchmark
  {
  SealedType[] sealedTypeArray = new SealedType[100];
  NonSealedType[] nonSealedTypeArray = new NonSealedType[100];
  [Benchmark(Baseline = true)]
  public Span NonSealed() => nonSealedTypeArray;
  [Benchmark]
  public SpanSealed() => sealedTypeArray;
  }
  public class BaseType {}
  public class NonSealedType : BaseType { }
  public sealed class SealedType : BaseType { }
  密封类的性能要高 50%:
  同样,这也是 IL 一模一样的,在 JIT 阶段做的优化,可以明显的看到,JIT 为非密封类单独做了类型检查:总结
  笔者在 FasterKvCache 代码中将一些类设置为sealed的原因显而易见:为了让类的职责更加清晰,在设计中没有计划让它有派生类为了性能的提升,JIT 优化可以让其方法调用更快
  还有更多有趣的东西(比如 IDE 智能提示将类设置为密封,如何使用 dotnet format 集成这些分析),大家可以翻阅原文或者 Weihan 大佬翻译的文章。https://www.meziantou.net/performance-benefits-of-sealed-class.htmhttps://mp.weixin.qq.com/s/dZlEjOB8jx0ku8eN8AhpzQ.NET性能优化交流群
  相信大家在开发中经常会遇到一些性能问题,苦于没有有效的工具去发现性能瓶颈,或者是发现瓶颈以后不知道该如何优化。于是很高兴的在这里宣布,我创建了一个专门交流.NET性能优化经验的群组,主题包括但不限于:如何找到.NET性能瓶颈,如使用APM、dotnet tools等工具.NET框架底层原理的实现,如垃圾回收器、JIT等等如何编写高性能的.NET代码,哪些地方存在性能陷阱
  希望能有更多志同道合朋友加入,分享一些工作中遇到的.NET性能问题和宝贵的性能分析优化经验。由于已经达到200人,可以加我微信,我拉你进群: ls1075
  参考资料
  [1]
  performance-benefits-of-sealed-class: https://www.meziantou.net/performance-benefits-of-sealed-class.htm
  [2]
  这里: https://learn.microsoft.com/zh-cn/dotnet/api/system.reflection.emit.opcodes.callvirt?view=net-7.0

全球有名的十大富豪,500亿美元身家都没上榜?有我国富豪吗?在经济发展的过程当中,也造就了非常多的富豪,全球各国的老百姓根据所处的行业不同,赚的钱的多少也有差异,不过,各个国家都有富豪的出现,很多富豪在全球的范围内都是能够排得上号的。能够成男子在单位午休时猝死,未签劳动合同,家属索赔百余万遭拒,工伤认定进行中,律师证明劳动关系证据分多种在广州打工的一川籍男子中午在单位午休时没有醒来,工友发现后立即拨打120,后经抢救无效不幸辞世,被认定为猝死。家属称,单位未与他签订劳动合同,索赔百余万遭拒。8月2日,当地人社部门开始了!以前所未有的方式接近台岛!演习区上空无民用飞机据央视新闻消息中国人民解放军北京时间8月4日1200至7日1200在台湾岛周围海域和空域进行重要的军事演习并组织实弹本次实战演练选取环岛六个区域,在这段时间,有相关的船舶和飞机请勿解放军环岛军演,会不会直接收复台湾,真的有可能文夏季风图我心依旧今日(8月4日)12时,中国人民解放军最重要军事演训正式开始,连续演习三天的时间,直到8月7日12时正式结束。这次军演,全部是实弹射击。此次实战演训选择环台湾岛六台湾对大陆经济高度依赖,这次经贸限制可以击中其痛点吗?这几天佩洛西老巫婆违反规则,窜访台湾就是对我们中国的最大挑衅,还从来没有见过这么嚣张的老巫婆。一把年纪了,穿着粉色衣服,难看死了同时,她可能会有自己的政治目的,但是她这么一挑衅会让台海军演,蔡英文之台湾当局如何应对?2022年8月4日中午12时,浩浩荡荡的台海军演正式拉开帷幕。据台媒报道,台军因应情势,清晨下令台军三军地区轮值的战备部队,将原兵力为连级的战斗队,立即提升为营级的特遣队,实施备战炎亚纶退出只有一个中国粉丝群,本人回应质疑完全不在意相信最近大家浏览网络的时候,都被同一件事刷屏,加上众多明星集体转发央视新闻的动态,只有一个中国理念在全网飞速传播。每次遇到此类事件,就是网友检验台湾艺人立场的时候,看他们会不会明确和美德S2061折叠电动代步车无需任何工具可一键折叠小巧便携性价比很高的一款手动折叠代步车,曾获红点国际设计大奖,和美德S2061折叠电动代步车一键折叠小巧便携满足航空标准可上飞机高铁!和美德S2061折叠电动代步车产品特点1。美国品牌,荣宁可热到脱水拉肚子也不开空调,家长的苦难式教育,已经过时了?很多家长和子女之间存在很大代沟,小的时候还不是很明显,家长说什么学生都会照做。家长自以为教育得当,等到学生长大后才发现,很多教育方式都只是在自我感动,并没有什么教育意义。对于大多数从军事角度解读中华一统的历史性契机,感谢佩洛西8月2日晚十时,佩洛西专机降落台湾松山机场,确认降落的那一刻,我相信但凡有点血性的中国人都感受到了一种屈辱,一种挑衅。恨不得立刻就能奔赴前线,向所有挑衅民族感情的敌对势力倾泻怒火。论刀工,我们中国人才是祖宗在论坛上看到有同学看不懂我们现在封锁台湾而又不打台湾,我就来解释一下这个是阳谋,跟用兵的兵法不一样。兵法讲究出其不意,而什么是阳谋呢?就是我明明白白告诉你我要干什么,而且我还告诉你
2023年1月15日IOS的AppStore软件限免8个APP推荐1。别低头用耳机监测低头行为信息原价6元,中文软件无内购无广告。软件描述在您低头达到一定幅度并维持一定时长时,对您进行提醒,让您及时纠正不良姿势。需要配合AirPodsPro3MaDenon110周年纪念DCDA110搭配BampampampW702签名版落地音箱BowersWilkinsBW(宝华韦健)素来以标杆级英国声代表品牌为人所熟悉。一方面,BW的50年坚持与传承,沉淀下来的技术工艺与声音理解,不仅受到发烧圈子的一致好评,还拥有音响这些事不注意,一个月电费上千元!快过年了最近天气实在是冷必须赶紧提个醒这些事现在做还不晚再不注意您过几天又要开始问电费咋这么高啊就像前不久一位居民12月份电费账单上了热搜仔细检查却发现(图片来自网络,如有侵权请联冰箱彩电已经不能满足了!合创V09要做电竞房在刚刚结束的广州车展上,合创发布了旗下的第四款车型,也是首款MPV车型合创V09。新车一经发布就吸引了大家的目光,尤其在各大社交平台上,关于合创V09的讨论热度相当高。极具辨识度的除尘纳新,这5款清洁小家电,送人自用都合适还有一周就要过年了,相信很多朋友都开始忙着给家里除尘纳新,同时也忙着在思考,年底到底给父母送点什么贴心又实用的东西。那本文,我就趁着年货节,来给大家推荐五款清洁小家电,每一款都非常全回来了!大数据看张家界有多火爆!网友张家界的雪一定要看一次2023刚开始半个月,张家界已经强势归来!随着新年的第一场雪落在张家界,来张家界看雪的游客也越来越多,一个好消息也传来张家界接待游客创下历史纪录!张家界天门山。图通讯员谭鹏波赵锐丁陈戌源自曝困难压力大!为国足操碎了心,甚至为此患上了抑郁症1月15日,经过近2个月时间的调查,相关部门针对李铁的调查取得了阶段性的进展,相信不久就会有结果!据了解,相关部门已经开启新一轮的调查,中国足坛被搞得人人自危苦不堪言,甚至有人为了破天荒刘奕被免职,足协30年来无人辞职历史会重写吗?乱球侃18谢谢您的阅读!如果可以,敬请点个关注,方便交流免去刘奕的中国足协秘书长职务据多方媒体,1月15日,中国足协第十一届执委会第八次会议决定,免去足协第一位非体制内背景的秘书长刘奕的中国人民领袖我们仍然要依靠人民创造新的历史伟业2022年10月23日,刚刚在中国共产党第二十届中央委员会第一次全体会议上当选的中共中央总书记习近平和中共中央政治局常委李强赵乐际王沪宁蔡奇丁薛祥李希在北京人民大会堂同采访中共二十南京公布了2023年景区免费开放日近日,南京公布了2023年景区免费开放日。3月26日,星期日,春暖花开,带上家人一起去游玩吧,园博园景区大,环境好,可参观的景点多,值得推荐的有先锋书店,江苏十三园,非常适合一家老女人再懒,也别穿一身黑出门,很土!瞧这3种配色多洋气想要牢牢把握冬季的时尚和温度,我们就需要协调出一套足以让自己满意的时尚妆造。从衣服的选择到配色的考量,我们需要打破层层叠叠的刻板印象,在对每一套着装严阵以待的同时,也要考虑到自我身