专栏电商日志财经减肥爱情
投稿投诉
爱情常识
搭配分娩
减肥两性
孕期塑形
财经教案
论文美文
日志体育
养生学堂
电商科学
头戴业界
专栏星座
用品音乐

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

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

前列腺是男人的生命腺,想要保护好它,希望你别做这5件事想必男性对于前列腺的健康都会格外关注,毕竟这个器官关系着男性的生殖健康。如果前列腺出现问题,不仅会引起腹部疼痛尿频尿急等症状,还会对男性的性功能造成危害,甚至可造成不育。因此,说前有效睡眠,不只是看时长?自测你的睡眠质量是否达标在大众的理解中8小时是最佳睡眠时间。但睡眠时长因人而异,随着年龄的增长,睡眠时间逐渐缩短,尤其是中老年人,每天睡眠时间只有56小时。睡眠的质量不仅取决于睡眠的总时长,还取决于睡眠周护胃保肠的饮食帮助(二)好医生为健康护航胃痛是临床上十分常见的症状,它的原因复杂多种,主要是由胃部疾病所致(如胃炎胃溃疡十二指肠溃疡等),也可由其他疾病牵涉引起(如胰腺炎胆囊炎等)。胃痛分为急性胃痛和慢性饮食不能太清淡?181个国家共同研究吃得越咸,寿命越长?食盐是我们厨房中经常用到的一种调味品,人们炒菜的时候几乎都少不了食盐,或许少放其他的调味品影响不大,但是少了食盐就会让饭菜吃起来索然无味,味同嚼蜡。很多人了解到食盐摄入过多的话,会国乒大姐大!32击败日本两大王牌后,世青赛完美收官目前,国乒主力选手都在参加国内的乒超联赛。而全球最优秀的U19和U15乒乓球运动员们,正在突尼斯参加为期一周的2022年国际乒联世界青年锦标赛。在突尼斯举办的世青赛有三大项单打双打小蝌蚪找妈妈小铁精读版宝宝你看这个封面上有什么呀?在一个开满荷花的池塘里面有一只青蛙和一群黑色的小蝌蚪,他们面对着面就相你和妈妈现在一样,他们好像在说话呢,他们在说什么呢?咱们今天一起看看,小蝌蚪到底和孕期总失眠是什么原因?有什么解决办法吗?2022育儿季导读怀孕对于妈妈们来说都是一件非常艰辛的事情,这不仅仅是身体的负担变重,很多孕期的各种问题困扰也让孕妈们感到身心疲惫。就拿孕期的睡眠来说,在早期睡眠状态还好,然而一到一个新手妈妈,是这样被毁掉的时间回到18年12月大宝出生的那一天,彼时因为爸妈担心已经在医院住了一星期。经历了催产给药等一系列的方式后,孩子仍在肚子里呆的稳稳的,医生和我们说的建议刨宫产手术。13号早晨,大宝2022年十大出圈小城旅行就像是两点一线生活中出现的意外,是无趣日子里的一抹亮色。回看2022,变化和不确定是旅行的常态,旅行计划经常容易被打乱,做再多的攻略和计划都不如先踏出家门一步。当远方难以抵达,5个被重新发现的古代失落城市还有什么比发现失落的城市更令人兴奋的呢?在世界各地,只要提到一座被重新发现的失落之城,我们的耳朵就会振作起来,因为我们都是浪漫主义者,内心充满好奇心!我们是在童话故事和埋藏的宝藏中老挝喜提中国修铁路,9个月接待170万游客,越南很不开心编辑科科图源网络(侵删)火车一响,黄金万两。老挝喜提中国修铁路,运行9个月,接待游客170万。越南听后很不开心,肠子都要悔青了,这是怎么回事?这条铁路是什么?又有哪些修建难点呢?中
一场仁马一次朋友圈的扩大鸣枪开赛。(博捷体育供图)春暖花开,活力开跑。3月12日上午8时30分,信利2023眉山仁寿半程马拉松暨全国半程马拉松锦标赛(眉山站)跑遍四川(眉山站)在仁寿县鸣枪开赛,身着鲜艳服大马丁拍卖世界杯决赛手套获4。5万美元捐给阿根廷儿童医院据阿根廷媒体的报道,阿根廷国门埃米利亚诺马丁内斯的世界杯决赛手套拍卖出了4。5万美元的价格,而这位阿根廷人也将获得的资金将捐献给阿根廷一家儿童医院的肿瘤科。而对于拍卖这双世界杯决赛AI基础数据服务行业研究新场景催化数据采标需求加速释放(报告出品方国金证券)1。AI基础数据服务脱胎于专业数据标注需求,2025年国内百亿规模可期1。1产业图谱AI基础数据服务脱胎于专业数据采标分工需求国内AI基础数据服务产业主要包括十人九痔,分享一个中成药,不用手术,让你不做有痔之士得了痔疮的人,要么觉得忍一忍就过去了,要么选择手术治疗,但是痔疮这个东西实在是反复无常,经常走了又来。大家好,我是刘医生,俗话说,十人九痔,现在生活中有痔疮的人不在少数,今天刘医生西部航空正式恢复运营重庆至普吉国际航线3月10日上午1030,海航航空集团旗下西部航空正式恢复运营重庆至普吉国际航线,并在江北国际机场T3航站楼举行重庆普吉国际航线首航庆祝仪式。此次的重庆至普吉往返航线是西部航空202两会即将结束,不出意外的话,百姓的生活将有以下几个改变今天上午人大举行了闭幕式,标志着两会正式结束了,然而,虽然两会结束了,但是老百姓对他的关注度却依然有增无减,因为两会上的一些议案很可能会在接下来陆续实施。特别是其中有些关系到民生的开国上将身世存疑,湖北两地长期扯皮,起因源自将军故意和稀泥?1614名开国将军,各有各的精彩。从目不识丁的小铁匠,到长征时期的红军师长,再到统帅几万人的解放军第一军军长,进而成为新中国的开国上将,贺炳炎的一生充满传奇。在57名开国上将中,他2023年3月11日广州动物园爆满原因分析广州动物园3月11日爆满,成千上万的游客涌入园区,使得园内的道路和展区都变得异常拥挤。据报道,这是广州动物园自开园以来最拥挤的一天。分析人士指出,该事件的原因可能是多方面的。一方面高血压的罪魁祸首不是盐,而是它!相信都听说了吃饭口味不能太咸盐不要吃太多,怕引发高血压。其实不是盐,而是盐中的钠。还有食物本身也有钠。避免食物本身钠摄入有下面4条口诀。另外,要多吃含钙的食物。因为钙离子能抵抗钠离花茶养生,保温杯里泡枸杞真的适合你吗?关于花茶养生的话题,最近疫情放开以后,很多朋友阳了以后,特别注重自己身体的身体状况的调理,于是开始了养生之旅。我自己作为养生界的一员有话要说。首先,近期的疫情以后的杨康,还是甲流以3种材料,1匙白糖,教你煎出外脆里糯红枣甜薄撑3种材料,1匙白糖,教你煎出外脆里糯红枣甜薄撑关注大胖友图图,每天都能看到新奇,简单,美味又实用的食谱哦广东有一个用糯米做的传统煎饼叫做薄撑,有甜有咸。用到的材料都很简单,今天就用
友情链接:快好找快生活快百科快传网中准网文好找聚热点快软网