都说不要装箱,那装箱到底带来了什么开销?
生活随笔
收集整理的這篇文章主要介紹了
都说不要装箱,那装箱到底带来了什么开销?
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
相信很有朋友在面試時大多會被問到 裝箱 的問題,也是一個經典的問題,可深可淺,那今天我們就從 匯編 和 內存 角度進行統一解讀下。
為了方便演示,先上一段裝箱的代碼。
class?Program{static?void?Main(string[]?args){var?i?=?10;var?o?=?(object)i;Console.ReadLine();}}接下來用 windbg 看一下它的匯編代碼。
0:000>?!U?/d?022e089a Normal?JIT?generated?code ConsoleApp1.Program.Main(System.String[]) Begin?022e0848,?size?5bD:\net5\ConsoleApp1\ConsoleApp1\Program.cs?@?15: 022e0872?c745f80a000000??mov?????dword?ptr?[ebp-8],0AhD:\net5\ConsoleApp1\ConsoleApp1\Program.cs?@?17: 022e0879?b9a8429e62??????mov?????ecx,offset?mscorlib_ni!System.Text.Encoding.GetEncodingCodePage(Int32)$##6006719?<PERF>?(mscorlib_ni+0x142a8)?(629e42a8)???????????//?獲取編碼類型 022e087e?e845282ffe??????call????005d30c8?(JitHelp:?CORINFO_HELP_NEWSFAST)??//生成一個初始化類型放在 eax 中。(objheader+methodtable+占位符) 022e0883?8945f0??????????mov?????dword?ptr?[ebp-10h],eax????????????????????//備份地址到?棧中 022e0886?8b45f0??????????mov?????eax,dword?ptr?[ebp-10h]????????????????????//恢復?eax?值 022e0889?8b55f8??????????mov?????edx,dword?ptr?[ebp-8]??????????????????????//將?0A?賦給?edx?上 022e088c?895004??????????mov?????dword?ptr?[eax+4],edx??????????????????????//將?edx?賦給?this.x?位置 022e088f?8b45f0??????????mov?????eax,dword?ptr?[ebp-10h]????????????????????//提取棧值到?eax?值 022e0892?8945f4??????????mov?????dword?ptr?[ebp-0Ch],eax????????????????????//將eax賦值給變量?o因為每句匯編代碼都有注釋,我就不解釋了,這里主要看一下 CORINFO_HELP_NEWSFAST方法,它是干什么的呢?這得從源碼說起:
/*?Allocating?a?new?object.?Always?use?ICorClassInfo::getNewHelper()?to?decide?which?is?the?right?helper?to?use?to?allocate?an?object?of?a?given?type.?*/CORINFO_HELP_NEW_CROSSCONTEXT,??//?cross?context?new?objectCORINFO_HELP_NEWFAST,CORINFO_HELP_NEWSFAST,??????????//?allocator?for?small,?non-finalizer,?non-array?objectCORINFO_HELP_NEWSFAST_FINALIZE,?//?allocator?for?small,?finalizable,?non-array?objectCORINFO_HELP_NEWSFAST_ALIGN8,???//?allocator?for?small,?non-finalizer,?non-array?object,?8?byte?alignedCORINFO_HELP_NEWSFAST_ALIGN8_VC,//?allocator?for?small,?value?class,?8?byte?alignedCORINFO_HELP_NEWSFAST_ALIGN8_FINALIZE,?//?allocator?for?small,?finalizable,?non-array?object,?8?byte?alignedCORINFO_HELP_NEW_MDARR,?????????//?multi-dim?array?helper?(with?or?without?lower?bounds?-?dimensions?passed?in?as?vararg)CORINFO_HELP_NEW_MDARR_NONVARARG,//?multi-dim?array?helper?(with?or?without?lower?bounds?-?dimensions?passed?in?as?unmanaged?array)CORINFO_HELP_NEWARR_1_DIRECT,???//?helper?for?any?one?dimensional?array?creationCORINFO_HELP_NEWARR_1_R2R_DIRECT,?//?wrapper?for?R2R?direct?call,?which?extracts?method?table?from?ArrayTypeDescCORINFO_HELP_NEWARR_1_OBJ,??????//?optimized?1-D?object?arraysCORINFO_HELP_NEWARR_1_VC,???????//?optimized?1-D?value?class?arraysCORINFO_HELP_NEWARR_1_ALIGN8,???//?like?VC,?but?aligns?the?array?startCORINFO_HELP_STRCNS,????????????//?create?a?new?string?literalCORINFO_HELP_STRCNS_CURRENT_MODULE,?//?create?a?new?string?literal?from?the?current?module?(used?by?NGen?code)可以看到,CORINFO_HELP_NEWSFAST 是用于分配 小對象,無終結器,非數組 的專用方法,也屬于高效的 快速分配路徑,那分配完之后的初始化長什么樣子呢?這就需要用 windbg 下斷點調試,從匯編代碼看,最后的結果會存放在 eax 上, 如下圖所示:
最后將棧上的10復制到堆上區域。
可以看到,這里涉及到了如下幾個性能開銷。
內存分配
風險在于分配引發的gc回收概率,比如判代回收 (臨時代,FullGC)。
多次內存復制 (stack -> heap -> register)
一個裝箱就有 6 個mov,反復的在 棧,堆,寄存器 之間交換。
增加 gc 回收壓力
gc本來工作壓力就很大,這又有無謂的分配,難哈。
最后就是如何解決,大概有如下兩點。盡可能避免裝箱 或者合理的使用 泛型。
總結
以上是生活随笔為你收集整理的都说不要装箱,那装箱到底带来了什么开销?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 关于OAuth2.0 Authoriza
- 下一篇: WPF 实现截屏控件之移动(二)(仿微信