整合營銷服務商

          電腦端+手機端+微信端=數(shù)據(jù)同步管理

          免費咨詢熱線:

          教你配置windows上的windbg,linux上

          教你配置windows上的windbg,linux上的lldb,快速打入clr內(nèi)部

          :背景

          1. 講故事

          前幾天公眾號里有位兄弟看了幾篇文章之后,也準備用windbg試試看,結(jié)果這一配就花了好幾天,(づ╥﹏╥)づ,我想也有很多躍躍欲試的朋友在配置的時候肯定會遇到這樣和那樣的問題,所以我覺得有必要整理一下,讓大家少走彎路。

          二:一些基礎(chǔ)概念

          1. 在哪下載

          現(xiàn)在安裝windbg越來越麻煩,還要安裝Windows 10 SDK,很多人就栽在這里,其實大家可以直接在網(wǎng)上找一鍵打包的windbg 6.0版本即可,才30多M,調(diào)生產(chǎn)調(diào)本地都很方便,順帶還可以練練SOS命令。

          云盤:https://pan.baidu.com/s/1VqXVIGVHxAZVPNds1525Jg 提取碼:mahg

          外網(wǎng):http://www.33lc.com/soft/96743.html

          2. 版本問題

          解壓打開會有一個x64和x86文件夾,很顯然,32位的程序用x86下的windbg調(diào)試,64位的程序用x64的windbg調(diào)試,如下圖:

          3. 其他的問題

          我比較喜歡用64bit程序,所以這里使用64位的windbg。

          <1> 配置微軟公有符號

          符號其實就是pdb文件,我們在debug模式下編譯項目都會看到這個,它的作用會對dll進行打標,這樣在調(diào)試時通過pdb就能看到局部變量,全局變量,行號等等其他信息,在FCL類庫中的pdb文件就放在微軟的公有服務器上,SRV*C:\mysymbols*http://msdl.microsoft.com/download/symbols。

          <2> 理解sos.dll和clr.dll

          很多時候大家都是事后調(diào)試,所以需要在生產(chǎn)上抓一個dump文件,為了將dump文件逆向到clr上的運行時狀態(tài),你必須要尋找到當時運行程序clr版本,同時也要找到對應clr版本的sos.dll,他們通常是在一起的,sos 就是 你 和 clr交互的渠道,很多人都卡在尋找正確版本的sos和clr版本上。。。如果不清楚,我可以畫張圖。

          有了這個前置基礎(chǔ),接下來就可以在windows和centos上進行配置實踐了。。。

          三. windows上的 netcore 3.1 配置

          為了演示,我先上一段簡單的代碼:

          
                  static void Main(string[] args)
                  {
                      var info="hello world!";
                      Console.WriteLine(info);
                      Console.ReadLine();
                  }
          

          1. 尋找clr.dll

          在netcore中,clr的名字變成了 coreclr.dll,路徑: C:\Program Files\dotnet\shared\Microsoft.NETCore.App.1.3

          2. 尋找sos.dll

          netcore3.0開始,sos就沒有放在版本號文件下了,詳見 SOS_README.md 內(nèi)容。

          
          SOS and other diagnostic tools now ship of band and work with any version of the .NET Core runtime.
          SOS has moved to the diagnostics repo here: https://github.com/dotnet/diagnostics.git.
          Instructions to install SOS: https://github.com/dotnet/diagnostics#installing-sos.
          

          看了上面文檔,大概意思就是說老版本的windbg,需要通過小工具dotnet-sos 自己生成一個sos.dll,那就按照文檔來吧

          
          PS C:\WINDOWS\system32> dotnet tool install -g dotnet-sos
          You can invoke the tool using the following command: dotnet-sos
          Tool 'dotnet-sos' (version '3.1.122203') was successfully installed.
          PS C:\WINDOWS\system32> dotnet-sos install
          Installing SOS to C:\Users\hxc\.dotnet\sos from C:\Users\hxc\.dotnet\tools\.store\dotnet-sos\3.1.122203\dotnet-sos\3.1.122203\tools\netcoreapp2.1\any\win-x64
          Installing over existing installation...
          Creating installation directory...
          Copying files...
          Execute '.load C:\Users\hxc\.dotnet\sos\sos.dll' to load SOS in your Windows debugger.
          Cleaning up...
          SOS install succeeded
          PS C:\WINDOWS\system32>
          

          仔細看輸出,sos.dll 已經(jīng)生成好了,接下來在任務管理器中生成一個dump文件,然后使用 .load 命令把 coreclr 和 sos 加載進去即可。

          
          .load C:\Users\hxc\.dotnet\sos\sos.dll
          .load C:\Program Files\dotnet\shared\Microsoft.NETCore.App\3.1.3\coreclr.dll
          

          最后我們抓一下 info 變量在堆上的分布。

          0:000> ~0s
          ntdll!ZwReadFile+0x14:
          00007ff8`3228aa64 c3              ret
          
          0:000> !clrstack -l
          OS Thread Id: 0x41d4 (0)
          
          000000246097EA40 00007FFF89C50F97 Error: Fail to initialize CoreCLR 80131022
          ConsoleApp5.Program.Main(System.String[])
              LOCALS:
                  0x000000246097EA68=0x0000021d8141aba8
          
          0:000> !do 0x0000021d8141aba8
          Name:        System.String
          MethodTable: 00007fff89cd1e18
          EEClass:     00007fff89cc2128
          Size:        46(0x2e) bytes
          File:        C:\Program Files\dotnet\shared\Microsoft.NETCore.App\3.1.3\System.Private.CoreLib.dll
          String:      hello world!
          Fields:
                        MT    Field   Offset                 Type VT     Attr            Value Name
          00007fff89c1b1e8  4000242        8         System.Int32  1 instance               12 _stringLength
          00007fff89c18000  4000243        c          System.Char  1 instance               68 _firstChar
          00007fff89cd1e18  4000244      110        System.String  0   static 0000021d81411360 Empty
          

          好了,windows上的netcore調(diào)試就這么簡單,希望這些配置能節(jié)省您的時間。

          四. windows 上的 netframework 配置

          framework程序比netcore配置要方便的多,不需要自己去生成sos了,如下代碼所示:

          
          64位程序加載路徑
          
           .load C:\Windows\Microsoft.NET\Framework64\v4.0.30319\sos.dll
           .load C:\Windows\Microsoft.NET\Framework64\v4.0.30319\clr.dll
          
          32位程序加載路徑
          
           .load C:\Windows\Microsoft.NET\Framework\v4.0.30319\sos.dll
           .load C:\Windows\Microsoft.NET\Framework\v4.0.30319\clr.dll
          

          五. centos 上的 netcore 3.1 配置

          首先要明白,對于linux內(nèi)核windbg就失效了,那怎么調(diào)試呢? 有兩種方式。

          1. 使用netcore內(nèi)置的dotnet-dump 小工具

          這個工具的地方在于,sos和clr都不需要你配置,直接使用它生成dump,然后直接調(diào)試,方便至極,下面看看怎么安裝,開兩個terminal,如下代碼:

          
          terminal 1:
          
          [root@10-25-198-96 data]# dotnet build
          [root@10-25-198-96 netcoreapp3.1]# dotnet data.dll
          hello world
          
          
          terminal 2:
          
          [root@10-25-198-96 cs2]# ps -ef | grep dotnet
          root     31555 31247  0 22:28 pts/0    00:00:00 dotnet cs2.dll
          root     32112 31995  0 22:29 pts/2    00:00:00 grep --color=auto dotnet
          
          [root@10-25-198-96 cs2]# dotnet tool install -g dotnet-dump
          You can invoke the tool using the following command: dotnet-dump
          Tool 'dotnet-dump' (version '3.1.122203') was successfully installed.
          [root@10-25-198-96 cs2]# export PATH=$PATH:$HOME/.dotnet/tools
          [root@10-25-198-96 cs2]# dotnet-dump collect --process-id 31555
          Writing full to /cs2/core_20200508_223204
          Complete
          

          可以看到dump文件已經(jīng)好了 /cs2/core_20200508_223204 ,接下來用 dotnet-dump 對dump文件調(diào)試。

          
          [root@10-25-198-96 cs2]# dotnet-dump analyze /cs2/core_20200508_223204
          Loading core dump: /cs2/core_20200508_223204 ...
          Ready to process analysis commands. Type 'help' to list available commands or 'help [command]' to get detailed help on a command.
          Type 'quit' or 'exit' to exit the session.
          > clrstack -l                                                                                              
          OS Thread Id: 0x7b43 (0)
                  Child SP               IP Call Site
          00007FFDFCABF2D0 00007fb0397af7fd [InlinedCallFrame: 00007ffdfcabf2d0] Interop+Sys.ReadStdin(Byte*, Int32)
          00007FFDFCABF2D0 00007fafbebbb4db [InlinedCallFrame: 00007ffdfcabf2d0] Interop+Sys.ReadStdin(Byte*, Int32)
          00007FFDFCABF2C0 00007FAFBEBBB4DB ILStubClass.IL_STUB_PInvoke(Byte*, Int32)
          
          00007FFDFCABF9D0 00007FAFBECF844D System.Console.ReadLine()
          
          00007FFDFCABF9E0 00007FAFBEBB037D cs2.Program.Main(System.String[]) [/cs2/Program.cs @ 13]
              LOCALS:
                  0x00007FFDFCABF9F0=0x00007faf980081d8
          
          00007FFDFCABFD08 00007fb037fc0f7f [GCFrame: 00007ffdfcabfd08] 
          00007FFDFCAC01F0 00007fb037fc0f7f [GCFrame: 00007ffdfcac01f0] 
          > dumpobj 0x00007faf980081d8                                                                               
          Name:        System.String
          MethodTable: 00007fafbec30f90
          EEClass:     00007fafbeb9e1b0
          Size:        44(0x2c) bytes
          File:        /usr/share/dotnet/shared/Microsoft.NETCore.App/3.1.3/System.Private.CoreLib.dll
          String:      hello world
          Fields:
                        MT    Field   Offset                 Type VT     Attr            Value Name
          00007fafbec2a0e8  400022a        8         System.Int32  1 instance               11 _stringLength
          00007fafbec26f00  400022b        c          System.Char  1 instance               68 _firstChar
          00007fafbec30f90  400022c      108        System.String  0   static 00007faf97fff360 Empty
          >    
          

          就這么簡單,不過這個工具雖好,但是不能調(diào)試非托管堆,而且命令也不是太多,當然夠我們平時用了。

          2. 使用linux專屬的lldb調(diào)試器

          要想實現(xiàn)windbg級別的調(diào)試,可以使用lldb調(diào)試器,這個非常強大,這里我也來介紹一下吧。

          <1> 安裝lldb

          lldb是使用C++寫的,也可以在 https://github.com/dotnet/diagnostics/blob/master/documentation/building/linux-instructions.md 尋找安裝辦法。

          
          sudo yum install centos-release-SCL epel-release
          sudo yum install cmake cmake3 gcc gcc-c++ gdb git libicu libunwind make python27 tar wget which zip
          cd $HOME
          git clone https://github.com/dotnet/diagnostics.git
          $HOME/diagnostics/documentation/lldb/centos7/build-install-lldb.sh
          

          一陣抽搐后就安裝好了,從下面可以看到目前版本是3.9.1。

          
          [root@10-25-198-96 cs2]# lldb -v
          lldb version 3.9.1 ( revision )
          

          <2> 尋找sos.dll

          跟windbg一樣,你需要生成一個sos.dll 。。。 同樣也是使用 dotnet-sos 生成。

          
          [root@10-25-198-96 cs2]# dotnet tool install -g dotnet-sos
          You can invoke the tool using the following command: dotnet-sos
          Tool 'dotnet-sos' (version '3.1.122203') was successfully installed.
          [root@10-25-198-96 cs2]# dotnet-sos install
          Installing SOS to /root/.dotnet/sos from /root/.dotnet/tools/.store/dotnet-sos/3.1.122203/dotnet-sos/3.1.122203/tools/netcoreapp2.1/any/linux-x64
          Installing over existing installation...
          Creating installation directory...
          Copying files...
          Updating existing /root/.lldbinit file - LLDB will load SOS automatically at startup
          Cleaning up...
          SOS install succeeded
          

          從上面信息看,sos 是安裝在 /root/.dotnet/sos 目錄下,同時也看到在lldb啟動的時候會自動加載sos.dll 。。。

          <3> 使用createdump 生成dump文件

          每個dotnet版本下都有一個createdump程序,可以用它生成dump文件,具體配置文檔可以參見:

          https://github.com/dotnet/diagnostics/blob/master/documentation/debugging-coredump.md

          https://github.com/dotnet/runtime/blob/master/docs/design/coreclr/botr/xplat-minidump-generation.md#configurationpolicy

          [root@10-25-198-96 cs2]# ps -ef | grep dotnet
          root     31555 31247  0 22:28 pts/0    00:00:00 dotnet cs2.dll
          root     32112 31995  0 22:29 pts/2    00:00:00 grep --color=auto dotnet
          
          [root@10-25-198-96 cs2]# find / -name createdump
          /usr/share/dotnet/shared/Microsoft.NETCore.App/3.1.3/createdump
          
          [root@10-25-198-96 3.1.3]# ./createdump 31555  -f /lldb/test.dump
          Writing minidump with heap to file /lldb/test.dump
          Written 84692992 bytes (20677 pages) to core file
          
          [root@10-25-198-96 3.1.3]# lldb --core /lldb/test.dump
          (lldb) target create --core "/lldb/test.dump"
          Core file '/lldb/test.dump' (x86_64) was loaded.
          (lldb) clrstack -l
          OS Thread Id: 0x7b43 (1)
          00007FFDFCABF9E0 00007FAFBEBB037D cs2.Program.Main(System.String[]) [/cs2/Program.cs @ 13]
              LOCALS:
                  0x00007FFDFCABF9F0=0x00007faf980081d8
          
          00007FFDFCABFD08 00007fb037fc0f7f [GCFrame: 00007ffdfcabfd08] 
          00007FFDFCAC01F0 00007fb037fc0f7f [GCFrame: 00007ffdfcac01f0] 
          (lldb) dumpobj 0x00007faf980081d8
          Name:        System.String
          MethodTable: 00007fafbec30f90
          EEClass:     00007fafbeb9e1b0
          Size:        44(0x2c) bytes
          File:        /usr/share/dotnet/shared/Microsoft.NETCore.App/3.1.3/System.Private.CoreLib.dll
          String:      hello world
          Fields:
                        MT    Field   Offset                 Type VT     Attr            Value Name
          00007fafbec2a0e8  400022a        8         System.Int32  1 instance               11 _stringLength
          00007fafbec26f00  400022b        c          System.Char  1 instance               68 _firstChar
          00007fafbec30f90  400022c      108        System.String  0   static 00007faf97fff360 Empty
          (lldb) 
          

          可以看到,通過lldb也可以直接打入clr內(nèi)部啦。。。

          六: 總結(jié)

          我覺得這篇文章肯定能給很多朋友節(jié)省不少的時間,想起朱一旦的那句話:有錢人的快樂,就是這么樸實無華且枯燥, 哈哈~

          有使用數(shù)據(jù)集合操作的DevExtreme ASP.NET MVC控件都有DataSource()方法,與其他控制方法不同,DataSource()在DevExtreme JavaScript API中沒有直接對應物,盡管它的用途類似于DevExtreme數(shù)據(jù)層中的 Store。您可以使用 DataSource() 方法來配置來自不同來源的數(shù)據(jù)訪問:

          • CLR 對象
          • 控制器
          • JSON 格式的只讀數(shù)據(jù)
          • 數(shù)據(jù)
          • OLAP 多維數(shù)據(jù)集

          數(shù)據(jù)綁定控件(PivotGrid 除外)也具有 DataSourceOptions() 方法,它公開了一個構(gòu)建器,用于配置初始排序、過濾、分組和其他數(shù)據(jù)整形操作,構(gòu)建器的方法具有本節(jié)中描述的 JavaScript API 對應項。

          DevExtreme Complete Subscription官方最新版免費下載試用,歷史版本下載,在線文檔和幫助文件下載-慧都網(wǎng)

          CLR 對象

          您可以將DevExtreme ASP.NET MVC 控件綁定到 CLR 對象的集合:Array、List 或 IEnumerable。

          這些集合…

          • 可以來自控制器(通過 Model? 或 ViewData?);
          • 可以嵌入到 Razor 文件中(直接在 HTML 幫助器聲明中或在 @functions 塊中)。

          集合作為 ArrayStore 傳遞給客戶端,請注意,集合數(shù)據(jù)應該是 JSON 可序列化的。

          示例:將控件綁定到數(shù)組

          Razor C#

          @(Html.DevExtreme().Chart()
          .DataSource(new[] {
          new { Day="Monday", Oranges=3 },
          new { Day="Tuesday", Oranges=2 },
          new { Day="Wednesday", Oranges=3 },
          new { Day="Thursday", Oranges=4 },
          new { Day="Friday", Oranges=6 },
          new { Day="Saturday", Oranges=11 },
          new { Day="Sunday", Oranges=4 }
          })
          )

          Razor VB

          @(Html.DevExtreme().Chart() _
          .DataSource({
          New With {.Day="Monday", .Oranges=3},
          New With {.Day="Tuesday", .Oranges=2},
          New With {.Day="Wednesday", .Oranges=3},
          New With {.Day="Thursday", .Oranges=4},
          New With {.Day="Friday", .Oranges=6},
          New With {.Day="Saturday", .Oranges=11},
          New With {.Day="Sunday", .Oranges=4}
          })
          )

          示例:將控件綁定到模型

          本示例代碼展示了如何將 MultiView 控件綁定到 Model。

          View

          Razor C#

          @model List<DevExtreme.MVC.Demos.Models.Store>
          
          @(Html.DevExtreme().MultiView()
          .DataSource(Model)
          )

          Razor VB

          @ModelType List(Of DevExtreme.MVC.Demos.Models.Store)
          
          @(Html.DevExtreme().MultiView() _
          .DataSource(Model)
          )

          Model

          C#

          namespace DevExtreme.MVC.Demos.Models.SampleData {
          public partial class SampleData {
          public static Store[] Stores=new[] {
          new Store {
          ID=1,
          CompanyName="SuprMart",
          Address="702 SW 8th Street",
          City="Bentonville",
          },
          new Store {
          ID=2,
          CompanyName="El'Depot",
          Address="2455 Paces Ferry Road NW",
          City="Atlanta",
          },
          new Store {
          ID=3,
          CompanyName="K&S Music",
          Address="1000 Nicllet Mall",
          City="Minneapolis",
          }
          };
          }
          }

          VB

          Namespace DevExtreme.MVC.Demos.Models.SampleData
          Partial Public Class SampleData
          Public Shared Stores As Store()={
          New Store With {
          .ID=1,
          .CompanyName="SuprMart",
          .Address="702 SW 8th Street",
          .City="Bentonville"
          },
          New Store With {
          .ID=2,
          .CompanyName="El'Depot",
          .Address="2455 Paces Ferry Road NW",
          .City="Atlanta"
          },
          New Store With {
          .ID=3,
          .CompanyName="K&S Music",
          .Address="1000 Nicllet Mall",
          .City="Minneapolis"
          }
          }
          End Class
          End Namespace

          Controller

          C#

          using DevExtreme.MVC.Demos.Models.SampleData;
          
          namespace DevExtreme.MVC.Demos.Controllers {
          public class MultiViewController : Controller {
          public ActionResult Overview() {
          return View(SampleData.Stores);
          }
          }
          }

          VB

          Imports DevExtreme.MVC.Demos.Models.SampleData
          
          Namespace DevExtreme.MVC.Demos.Controllers
          Public Class MultiViewController
          Inherits Controller
          Public Function Overview() As ActionResult
          Return View(SampleData.Stores)
          End Function
          End Class
          End Namespace

          DataSource 方法重載接受 string[] 鍵參數(shù),因此您的代碼如下所示:

          C#

          .DataSource(Model.YourCollection, "KeyFieldName")

          VB

          .DataSource(Model.YourCollection, "KeyFieldName")

          DevExtreme

          DevExtreme擁有高性能的HTML5 / JavaScript小部件集合,使您可以利用現(xiàn)代Web開發(fā)堆棧(包括React,Angular,ASP.NET Core,jQuery,Knockout等)構(gòu)建交互式的Web應用程序。從Angular和Reac,到ASP.NET Core或Vue,DevExtreme包含全面的高性能和響應式UI小部件集合,可在傳統(tǒng)Web和下一代移動應用程序中使用。 該套件附帶功能齊全的數(shù)據(jù)網(wǎng)格、交互式圖表小部件、數(shù)據(jù)編輯器等。

          起棧想必會聽到這樣幾個關(guān)鍵詞:后進先出,先進后出,入棧,出棧。

          棧這種數(shù)據(jù)結(jié)構(gòu),數(shù)組完全可以代替其功能。

          但是存在即是真理,其目的就是避免暴露不必要的操作。

          如角色一樣,不同的情景或者角色擁有不同的操作權(quán)限。

          那我們來了解一下棧,棧是一種線性數(shù)據(jù)結(jié)構(gòu),并且只能從一端壓入或者彈出=添加或者刪除。

          基于數(shù)組實現(xiàn)的棧是順序棧,基于鏈表實現(xiàn)的鏈式棧。


          接下來我們看一下.Net 是怎么實現(xiàn)棧的?

          注釋說的很明白:這是一個基于數(shù)組實現(xiàn)的順序棧,其入棧復雜度O(n),出棧復雜度為O(1)

              // A simple stack of objects.  Internally it is implemented as an array,
              // so Push can be O(n).  Pop is O(1).
              [DebuggerTypeProxy(typeof(System.Collections.Stack.StackDebugView))] 
              [DebuggerDisplay("Count={Count}")]
              [System.Runtime.InteropServices.ComVisible(true)]
              [Serializable]
              public class Stack : ICollection, ICloneable {
                  private Object[] _array;     // Storage for stack elements
                  [ContractPublicPropertyName("Count")]
                  private int _size;           // Number of items in the stack.
                  private int _version;        // Used to keep enumerator in sync w/ collection.
                  [NonSerialized]
                  private Object _syncRoot;
              
                  private const int _defaultCapacity=10;
              
                  public Stack() {
                      _array=new Object[_defaultCapacity];
                      _size=0;
                      _version=0;
                  }

          入棧:我們也看到這個是基于數(shù)組并且支持的那個太擴容的棧,默認大小圍為10,當存滿之后就會兩倍擴容。

                  // Pushes an item to the top of the stack.
                  // 
                  public virtual void Push(Object obj) {
                      //Contract.Ensures(Count==Contract.OldValue(Count) + 1);
                      if (_size==_array.Length) {
                          Object[] newArray=new Object[2*_array.Length];
                          Array.Copy(_array, 0, newArray, 0, _size);
                          _array=newArray;
                      }
                      _array[_size++]=obj;
                      _version++;
                  }


          正如注釋中提到的,入棧復雜度可以達到O(n),出棧可以是O(1)  

          so Push can be O(n). Pop is O(1).  

          出棧Pop,復雜度為O(1)很好理解,

          上面提到的動態(tài)棧是操作受限的數(shù)組,并且不會產(chǎn)生新的內(nèi)存申請或者數(shù)據(jù)的搬移

          我們只要是獲取到最后一個,然后彈出(也就是刪除)即可。


          入棧Push,我們接下來分析一下出棧為什么復雜度為O(n):

          前面有一篇《算法復雜度》 https://www.cnblogs.com/sunchong/p/9928293.html ,提到過:最好、最壞、平均

          對于下面的入棧代碼:

          最好情況時間復雜度:不會有擴容和數(shù)據(jù)遷移,所以直接追加即可,復雜度為O(1)

          最壞情況時間復雜度:需要擴容后并且搬移原來n個數(shù)據(jù),然后再插入新的數(shù)據(jù),復雜度為 O(n)

          那么平均時間復雜度是多少呢?這里需要結(jié)合攤還分析法,進行復雜度分析。為什么這里要使用攤還分析法呢?


          先耐心地看看其定義:

          分析一個操作序列中所執(zhí)行的所有操作的平均時間分析方法。

          與一般的平均分析方法不同的是,它不涉及概率的分析,可以保證最壞情況下每個操作的平均性能。

          總結(jié)一下攤還分析:執(zhí)行的所有操作的平均時間,不扯概率。


          我們可以拿攤還分析來直接分析:

          public virtual void Push(Object obj) 
          {
           //Contract.Ensures(Count==Contract.OldValue(Count) + 1);
               if (_size==_array.Length) 
             {
                Object[] newArray=new Object[2*_array.Length];
                Array.Copy(_array, 0, newArray, 0, _size);
                 _array=newArray;
              }
              _array[_size++]=obj;
              _version++;
          }


          入棧的最壞情況復雜度是O(n),但是這個最壞情況時間復雜度是在n+1次插入的時候發(fā)生的,

          剩下的n次是不需要擴容搬移數(shù)據(jù),只是簡單的入棧 O(1),所以均攤下來的復雜度是O(1)。

          那么為什么微軟的工程師在備注里寫下push復雜度是O(n)?--這里指的是空間復雜度O(n)


          棧這種數(shù)據(jù)結(jié)構(gòu)的應用有很多場景,其中一種就是我們的線程棧或者說函數(shù)棧。

          當開啟一個線程時,Windows系統(tǒng)為每個線程分配一個1M大小的線程棧。分配這個用來干什么呢?

          存儲方法中的參數(shù)和變量。趁這個機會,我們了解一下CLR的內(nèi)存模型。

          首先對于C#代碼是如何編程機器代碼的呢?

          c#代碼 -> 編譯器 -> IL -> JIT -> CPU指令


          當一個線程執(zhí)行到以下方法時會有什么操作呢?

          這段代碼也很簡單,就是在Main方法中調(diào)用了GetCode()方法,其他的都是一些臨時變量。

                  static void Main(string[] args)
                  {
                      string parentCode="PI001";
                      string newCode=string.Empty;
                      newCode=GetCode(parentCode);
                  }
          
                  static string GetCode(string sourceCode)
                  {
                      string currentMaxCode="001001";
                      string newCode=$"{sourceCode}{currentMaxCode}";
                      return newCode;
                  }


          首先線程會分配1M內(nèi)存用于存儲臨時變量和參數(shù);

          進入Main方法時,會將參數(shù)和返回地址依次壓棧

          static void Main(string[] args)

          string parentCode="PI001";
          string newCode=string.Empty;



          接下來開始進入到 GetCode() 方法,此時與之前一樣壓入?yún)?shù)和返回地址


          string currentMaxCode="001001";
          string newCode=$"{sourceCode}{currentMaxCode}";



          既然說到了棧,那我們不得不再說一下托管堆,再來一段代碼圖解:

          這是父類和子類的具體代碼,可以略過此處。


          我們隱藏這些方法的具體實現(xiàn),只預覽他們的之間的關(guān)系:

          接下來,線程即將進入到下面的這個方法:

                  void GetProduct()
                  {
                      BaseProduct p;
                      string sourceCode;
                      p=new Product();
                      sourceCode=p.GetCode();
                      sourceCode=Product.GetNewCode(sourceCode);
                  }


          JIT在編譯到此方法前會注意到這個方法所有的引用類型,

          并向CLR發(fā)出通知,加載程序集,在托管對中創(chuàng)建相關(guān)的類型對象數(shù)據(jù)結(jié)構(gòu)。

          這也就是我們所能理解的靜態(tài)字段為什么不是在實例化的時候創(chuàng)建,

          而是在這個類型創(chuàng)建的時候就一直存在。

          這其實就是兩個概念,靜態(tài)資源是屬于類結(jié)構(gòu)的,而實例資源是屬于實例本身。

          下面的圖忽略String類型,因為String類型是常用類型可能在之前就已經(jīng)創(chuàng)建好了,

          類型對象包括:對象指針、同步塊索引、靜態(tài)資源、方法表,像下面這樣:


          BaseProduct p;
          string sourceCode;

          方法變量入棧,并且引用類型初始化為null


          p=new Product();

          實例化Product ,托管堆創(chuàng)建Product對象,并將這個對象的指針指向Product類型。

          將線程棧中的變量p指針,指向新創(chuàng)建的Product對象。



          sourceCode=p.GetCode();

          JIT找到這個變量p的Product對象,再找到對應的Product類型,表中找到此方法GetCode();

          當然這個方法實際是父類的方法,所以JIT會一直向上找,直到找到為止。

          圖中是個虛擬路線,計算結(jié)果賦值給 string sourceCode


          sourceCode=Product.GetNewCode(sourceCode);

          和上一步類似,只不過這次是調(diào)用的靜態(tài)方法。發(fā)出類型Product,靜態(tài)方法是GetNewCode()


          以上內(nèi)容就是 JIT、CLR、線程棧、托管堆的一些運行時關(guān)系。


          主站蜘蛛池模板: 一区二区三区四区在线观看视频| 国产伦一区二区三区高清| 亚洲欧美日韩一区二区三区在线 | 一区二区三区杨幂在线观看| 中文无码精品一区二区三区| 无码一区二区三区视频| 日韩毛片一区视频免费| 一区国产传媒国产精品| 免费观看一区二区三区| 日本一区二区高清不卡| 精品亚洲福利一区二区| 国产一区在线mmai| 国产MD视频一区二区三区| 日本无码一区二区三区白峰美| 亚洲国产成人久久综合一区77 | 国产一区二区三区在线观看免费| 色婷婷综合久久久久中文一区二区| 日本精品高清一区二区2021| 中文字幕一区日韩精品| 亚洲福利视频一区二区三区| 亚洲国产成人久久一区WWW | 亚洲一区免费视频| 精品无码人妻一区二区三区 | 无码人妻精品一区二区在线视频 | 久久成人国产精品一区二区| 日本一区二区三区免费高清在线| 久久精品无码一区二区WWW| 亚洲av鲁丝一区二区三区| 一级毛片完整版免费播放一区 | 国产福利酱国产一区二区| 怡红院一区二区在线观看| 亚洲AV无码一区二区三区牲色| 中文字幕日韩一区二区不卡 | 无码人妻啪啪一区二区| 毛片一区二区三区无码| 香蕉久久ac一区二区三区| 成人免费一区二区三区在线观看| 末成年女AV片一区二区| 亚洲视频一区在线观看| 伊人色综合一区二区三区影院视频 | 中文字幕一区二区三区人妻少妇|