国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Net 高級調(diào)試之十:輕量級代碼生成的調(diào)試

這篇具有很好參考價(jià)值的文章主要介紹了Net 高級調(diào)試之十:輕量級代碼生成的調(diào)試。希望對大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

一、簡介
    今天是《Net 高級調(diào)試》的第十篇文章。說起來,高級調(diào)試,調(diào)試的內(nèi)容還是挺多的,技巧也不少,但是,要想做一個(gè)合格的高級調(diào)試人員,還需要掌握如何調(diào)試動態(tài)生成的IL代碼。今天要探討的高級調(diào)試的技巧是如何調(diào)試通過 Emit 動態(tài)生成 IL 代碼。可能有人會問,我們不是編寫 C# 代碼,或者是 VB.Net 代碼嗎?怎么還要動態(tài)生成 IL 代碼,這些工作不是編譯器做的嗎?當(dāng)然,一般情況是這樣的,但是,當(dāng)我們編寫一些高性能的框架的時(shí)候,使用 IL 代碼編寫也是常事。既然也可以直接使用 IL 編寫代碼,那對它的調(diào)試也是少不了的,調(diào)試機(jī)會雖然很少,具有這個(gè)本領(lǐng),等遇到這樣的問題,就不至于慌亂了,俗話說的好:藝多不壓身。當(dāng)然了,第一次看視頻或者看書,是很迷糊的,不知道如何操作,還是那句老話,一遍不行,那就再來一遍,還不行,那就再來一遍,俗話說的好,書讀千遍,其意自現(xiàn)。
     如果在沒有說明的情況下,所有代碼的測試環(huán)境都是 Net Framewok 4.8,但是,有時(shí)候?yàn)榱瞬榭丛创a,可能需要使用 Net Core 的項(xiàng)目,我會在項(xiàng)目章節(jié)里進(jìn)行說明。好了,廢話不多說,開始我們今天的調(diào)試工作。

    ?? 調(diào)試環(huán)境我需要進(jìn)行說明,以防大家不清楚,具體情況我已經(jīng)羅列出來。
          操作系統(tǒng):Windows Professional 10
          調(diào)試工具:Windbg Preview(可以去Microsoft Store 去下載)
          開發(fā)工具:Visual Studio 2022
          Net 版本:Net Framework 4.8
          CoreCLR源碼:源碼下載

二、基礎(chǔ)知識

    1、動態(tài)代碼調(diào)試
        動態(tài)代碼調(diào)試的機(jī)會雖然不多,但是掌握動態(tài)代碼調(diào)試的技巧還是很有必要的,俗話說的好,藝多不壓身。當(dāng)我們遇到有這樣寫代碼,由此引發(fā)的問題的時(shí)候,我們也可以做到遇事不驚。
        今天我們就討論三種調(diào)試的技巧。

    2、三種調(diào)試策略

        2.1、捕獲 JIT 的?CompileMethod 方法。
            C# 代碼的編譯過程分為兩個(gè)階段,第一個(gè)階段就是編譯器的階段,這個(gè)階段編譯器將我們編寫的C#源代碼編譯成 IL 代碼,第二階段,就是在運(yùn)行的時(shí)候,JIT 將 IL 代碼編譯為機(jī)器代碼,我們的程序就運(yùn)行了。現(xiàn)在是動態(tài)生成的 IL 代碼,沒有第一個(gè)階段,直接就是第二個(gè) JIT 編譯的階段,我們可以嘗試在 JIT 的某個(gè)方法中設(shè)置斷點(diǎn)進(jìn)行攔截,拿到方法的描述符,也就是 MD,有了 MD,我們就可以使用 bp md 命令,為這個(gè)方法下斷點(diǎn),這樣就可以對動態(tài)生成的代碼進(jìn)行調(diào)試了。

        2.2、從代碼中獲取委托的函數(shù)指針(我的測試沒有實(shí)現(xiàn))。
            這種方法比較簡單,但需要在方法中加一行代碼,具有一定的破壞性。代碼:Marshal.GetFunctionPointerForDelegate(委托實(shí)例).ToInt64()。

        2.3、在動態(tài)的代碼中注入 Debugger.Break()。
            我們在很多的調(diào)試中都會用到 Debugger.Break() 函數(shù),讓程序中斷到調(diào)試器,如果這個(gè)動態(tài)代碼,我們具有完整的控制權(quán),我們就可以通過注入這個(gè)方法:Debugger.Break(),實(shí)現(xiàn) int 3 中斷,進(jìn)而獲取想要的數(shù)據(jù)。代碼如下:IL.Emit(OpCodes.Call,typeof(Debugger).GetMethod("Break"))。

    3、程序集
        3.1、程序集崩潰
            程序集泄露是指什么呢?就是程序的內(nèi)存暴漲,產(chǎn)生大量的程序集。

三、調(diào)試過程
    廢話不多說,這一節(jié)是具體的調(diào)試操作的過程,又可以說是眼見為實(shí)的過程,在開始之前,我還是要啰嗦兩句,這一節(jié)分為兩個(gè)部分,第一部分是測試的源碼部分,沒有代碼,當(dāng)然就談不上測試了,調(diào)試必須有載體。第二部分就是根據(jù)具體的代碼來證實(shí)我們學(xué)到的知識,是具體的眼見為實(shí)。

    1、測試源碼
        以下項(xiàng)目代碼就是在眼見為實(shí)用到的測試用例。
        1.1、Example_10_1_1
Net 高級調(diào)試之十:輕量級代碼生成的調(diào)試Net 高級調(diào)試之十:輕量級代碼生成的調(diào)試
 1 namespace Example_10_1_1
 2 {
 3     internal class Program
 4     {
 5         private delegate int AddDelegate(int a, int b);
 6         static void Main(string[] args)
 7         {
 8             var dynamicAdd = new DynamicMethod("Add", typeof(int), new Type[] { typeof(int), typeof(int) });
 9             var il = dynamicAdd.GetILGenerator();
10             il.Emit(OpCodes.Ldarg_0);
11             il.Emit(OpCodes.Ldarg_1);
12             il.Emit(OpCodes.Add);
13             il.Emit(OpCodes.Ret);
14 
15             var addDelegate = (AddDelegate)dynamicAdd.CreateDelegate(typeof(AddDelegate));
16             Console.WriteLine(addDelegate(10, 20));
17         }
18     }
19 }
View Code

        1.2、Example_10_1_2
Net 高級調(diào)試之十:輕量級代碼生成的調(diào)試Net 高級調(diào)試之十:輕量級代碼生成的調(diào)試
 1 namespace Example_10_1_2
 2 {
 3     internal class Program
 4     {
 5         private delegate int AddDelegate(int a, int b);
 6         static void Main(string[] args)
 7         {
 8             var dynamicAdd = new DynamicMethod("Add", typeof(int), new Type[] { typeof(int), typeof(int) });
 9             var il = dynamicAdd.GetILGenerator();
10             il.Emit(OpCodes.Ldarg_0);
11             il.Emit(OpCodes.Ldarg_1);
12             il.Emit(OpCodes.Add);
13             il.Emit(OpCodes.Ret);
14 
15             var addDelegate = (AddDelegate)dynamicAdd.CreateDelegate(typeof(AddDelegate));
16 
17             Console.WriteLine("Function Pointer:0x{0:x16}", Marshal.GetFunctionPointerForDelegate(addDelegate).ToInt64());
18 
19             Debugger.Break();
20 
21             Console.WriteLine(addDelegate(10, 20));
22         }
23     }
24 }
View Code

        1.3、Example_10_1_3
Net 高級調(diào)試之十:輕量級代碼生成的調(diào)試Net 高級調(diào)試之十:輕量級代碼生成的調(diào)試
 1 namespace Example_10_1_3
 2 {
 3     internal class Program
 4     {
 5         private delegate int AddDelegate(int a, int b);
 6         static void Main(string[] args)
 7         {
 8             var dynamicAdd = new DynamicMethod("Add", typeof(int), new Type[] { typeof(int), typeof(int) });
 9             var il = dynamicAdd.GetILGenerator();
10 
11             il.Emit(OpCodes.Call,typeof(Debugger).GetMethod("Break"));
12             il.Emit(OpCodes.Ldarg_0);
13             il.Emit(OpCodes.Ldarg_1);
14             il.Emit(OpCodes.Add);
15             il.Emit(OpCodes.Ret);
16 
17             var addDelegate = (AddDelegate)dynamicAdd.CreateDelegate(typeof(AddDelegate));
18 
19             Console.WriteLine(addDelegate(10, 20));
20         }
21     }
22 }
View Code

        1.4、Example_10_1_4
Net 高級調(diào)試之十:輕量級代碼生成的調(diào)試Net 高級調(diào)試之十:輕量級代碼生成的調(diào)試
 1 namespace Example_10_1_4
 2 {
 3     internal class Program
 4     {
 5         //XmlSerializer序列化程序集泄露解決辦法。
 6         //static readonly XmlSerializer xmlSerializer = new XmlSerializer(typeof(Customer), new XmlRootAttribute("FabrikamCustomer"));
 7         static void Main(string[] args)
 8         {
 9             var xml = @"<FabrikamCustomer><Id>001</Id><FirstName>John</FirstName><LastName>Dow</LastName></FabrikamCustomer>";
10 
11             Enumerable.Range(0, 30000)
12                 .Select(i => GetCustomer(i, "FabrikamCustomer", xml))
13                 .ToList();
14 
15             Console.WriteLine("處理完成!");
16             Console.ReadLine();
17         }
18 
19         public static Customer GetCustomer(int i, string rootElementName, string xml)
20         {
21             var xmlSerializer = new XmlSerializer(typeof(Customer), new XmlRootAttribute("FabrikamCustomer"));
22             using (var textReader = new StringReader(xml))
23             {
24                 using (var xmlReader = XmlReader.Create(textReader))
25                 {
26                     Console.WriteLine(i);
27 
28                     return (Customer)xmlSerializer.Deserialize(xmlReader);
29                 }
30             }
31         }
32     }
33 
34     public class Customer
35     {
36         public string Id { get; set; }
37         public string FirstName { get; set; }
38         public string LastName { get; set; }
39     }
40 }
View Code

    2、眼見為實(shí)
        項(xiàng)目的所有操作都是一樣的,所以就在這里說明一下,但是每個(gè)測試?yán)樱夹枰匦聠?,并加載相應(yīng)的應(yīng)用程序,加載方法都是一樣的。流程如下:我們編譯項(xiàng)目,打開 Windbg,點(diǎn)擊【文件】----》【launch executable】附加程序,打開調(diào)試器的界面,程序已經(jīng)處于中斷狀態(tài)。

        2.1、捕獲 JIT 的?CompileMethod 方法,為 Add 方法設(shè)置斷點(diǎn),進(jìn)行調(diào)試。
            測試源碼:Example_10_1_1

            Net 高級調(diào)試之十:輕量級代碼生成的調(diào)試

            上圖是我們的代碼,我們使用【!mbp】命令在18行下斷點(diǎn),【mbp】命令是 SOSEX的擴(kuò)展命令,執(zhí)行前必須加載 SOSEX.dll,我們需要使用【g】命令,繼續(xù)運(yùn)行程序,然后到達(dá)指定斷點(diǎn)處停止后。

1 0:000> !mbp Program.cs 18
2 The CLR has not yet been initialized in the process.
3 Breakpoint resolution will be attempted when the CLR is initialized.

            Net 高級調(diào)試之十:輕量級代碼生成的調(diào)試

            我們已經(jīng)在我們設(shè)置的斷點(diǎn)處暫停。我們開始對?CompileMethod 這個(gè)方法下斷點(diǎn)。首先我們通過【lm(load module)】命令找到clrjit.dll 這個(gè)dll。

 1 0:000> lm
 2 start    end        module name
 3 00f80000 00f88000   Example_10_1_1 C (service symbols: CLR Symbols with PDB: C:\ProgramData\...\Example_10_1_1.pdb)        
 4 5bd10000 5bdaf000   apphelp    (deferred)             
 5 6dbc0000 6efce000   mscorlib_ni   (service symbols: CLR Symbols with PDB: C:\ProgramData\...88BB3460CAC52\mscorlib.pdb)
 6 6efd0000 6f780000   clr        (pdb symbols)          C:\ProgramData\Dbg\sym\clr.pdb\5138062248484B79BCF6F6B3F3B59A3D2\clr.pdb
 7 721b0000 7223d000   mscoreei   (pdb symbols)          C:\ProgramData\Dbg\sym\mscoreei.pdb\3353E43482934F9AB820643DF51EC4692\mscoreei.pdb
 8 72240000 72292000   MSCOREE    (pdb symbols)          C:\ProgramData\Dbg\sym\mscoree.pdb\3A1E9FD59D013FF42905FC8655F33DCB1\mscoree.pdb
 9 722d0000 7235a000   clrjit     (deferred)             
10 72380000 7242b000   ucrtbase_clr0400   (deferred)             
11 ......        
12 77810000 77828000   win32u     (deferred)             
13 77830000 77ab0000   combase    (deferred)             
14 77ac0000 77c62000   ntdll      (pdb symbols)          C:\ProgramData\Dbg\sym\wntdll.pdb\DBC8C8F74C0E3696E951B77F0BB8569F1\wntdll.pdb
15 
16 Unloaded modules:
17 77830000 77ab0000   combase.dll

             紅色標(biāo)注的,說明CLR 和 JIT 都已經(jīng)加載了。然后,我們通過【x】命令查找 CompileMethod方法。

1 0:000> x clrjit!*CompileMethod*
2 722d3700          clrjit!CILJit::compileMethod (class ICorJitInfo *, struct CORINFO_METHOD_INFO *, unsigned int, unsigned char **, unsigned long *)

            我們找到了 CompileMethod 方法,給這個(gè)方法下一個(gè)斷點(diǎn)。

1 0:000> bp clrjit!CILJit::compileMethod

            我們【g】了兩次,已經(jīng)在 CILJit::compileMethod 方法處斷住了。

 1 0:000> g
 2 Breakpoint 1 hit
 3 eax=00000002 ebx=0133ef84 ecx=03383840 edx=00000000 esi=033824c8 edi=0133eedc
 4 eip=016c0a3d esp=0133ee8c ebp=0133eee8 iopl=0         nv up ei pl zr na pe nc
 5 cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
 6 Example_10_1_1!COM+_Entry_Point <PERF> (Example_10_1_1+0x740a3d):
 7 016c0a3d b9144e6601      mov     ecx,1664E14h
 8 0:000> g
 9 Breakpoint 0 hit
10 eax=72354698 ebx=80000004 ecx=722d3700 edx=00005c10 esi=7234b3fc edi=0133e970
11 eip=722d3700 esp=0133e7ac ebp=0133e804 iopl=0         nv up ei ng nz na po nc
12 cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000282
13 clrjit!CILJit::compileMethod:
14 722d3700 55              push    ebp

            我們在?CILJit::compileMethod 這個(gè)方法已經(jīng)斷住了,然后我們使用【!kb】命令,查看一下它的參數(shù)。

1 0:000> kb 1
2  # ChildEBP RetAddr      Args to Child              
3 00 0133e804 6f09ccc3     72354698 0133e970 0133e8e8 clrjit!CILJit::compileMethod [f:\dd\ndp\clr\src\jit32\ee_il_dll.cpp @ 151] 

            72354698 0133e970 0133e8e8 這個(gè)三個(gè)參數(shù)的第三參數(shù)其實(shí)就是包含方法描述符的地址。

1 0:000> dp 0133e8e8 l1
2 0133e8e8  01665384

            我們可以使用【!dumpmd】命令查看這個(gè)方法的信息。

1 0:000> !dumpmd 01665384
2 Method Name:  DynamicClass.Add(Int32, Int32)(我們要查找的方法)
3 Class:        016652f0
4 MethodTable:  01665344
5 mdToken:      06000000
6 Module:       01664eac
7 IsJitted:     no
8 CodeAddr:     ffffffff(說明方法還沒有編譯)
9 Transparency: Transparent

            我們使用【k】命令,看看我的調(diào)用棧。

 1 0:000> k
 2  # ChildEBP RetAddr      
 3 00 0133e804 6f09ccc3     clrjit!CILJit::compileMethod [f:\dd\ndp\clr\src\jit32\ee_il_dll.cpp @ 151] 
 4 01 0133e804 6f09cd9b     clr!invokeCompileMethodHelper+0x10b
 5 02 0133e84c 6f09cdf8     clr!invokeCompileMethod+0x3d
 6 03 0133e8b8 6f09d0a7     clr!CallCompileMethodWithSEHWrapper+0x39
 7 04 0133ec78 6f09caac     clr!UnsafeJitFunction+0x431
 8 05 0133ed6c 6f09e703     clr!MethodDesc::MakeJitWorker+0x40b
 9 06 0133ede4 6f08f78f     clr!MethodDesc::DoPrestub+0x5f3
10 07 0133ee60 6efdf4bb     clr!PreStubWorker+0xe0
11 08 0133ee84 016c0aab     clr!ThePreStub+0x11
12 09 0133eee8 6efdf036     Example_10_1_1!COM+_Entry_Point <PERF> (Example_10_1_1+0x740aab) [E:\Visual Studio 2022\Program.cs @ 19] 
13 0a 0133eef4 6efe22da     clr!CallDescrWorkerInternal+0x34
14 0b 0133ef48 6efe859b     clr!CallDescrWorkerWithHandler+0x6b
15 0c 0133efb0 6f18b11b     clr!MethodDescCallSite::CallTargetWorker+0x16a
16 0d 0133f0d4 6f18b7fa     clr!RunMain+0x1b3
17 0e 0133f340 6f18b727     clr!Assembly::ExecuteMainMethod+0xf7
18 0f 0133f824 6f18b8a8     clr!SystemDomain::ExecuteMainMethod+0x5ef
19 10 0133f87c 6f18b9ce     clr!ExecuteEXE+0x4c
20 11 0133f8bc 6f187305     clr!_CorExeMainInternal+0xdc
21 12 0133f8f8 721bfa84     clr!_CorExeMain+0x4d
22 13 0133f930 7224e81e     mscoreei!_CorExeMain+0xd6
23 14 0133f940 72254338     MSCOREE!ShellShim__CorExeMain+0x9e
24 15 0133f958 765ff989     MSCOREE!_CorExeMain_Exported+0x8
25 16 0133f958 77b27084     KERNEL32!BaseThreadInitThunk+0x19
26 17 0133f9b4 77b27054     ntdll!__RtlUserThreadStart+0x2f
27 18 0133f9c4 00000000     ntdll!_RtlUserThreadStart+0x1b

            我們生成的 Add 方法,會首先進(jìn)入??clr!MethodDesc::DoPrestub 樁函數(shù),開始引導(dǎo)JIT編譯,我們就在這個(gè)方法設(shè)斷點(diǎn)。

1 0:000> bp 6f08f78f

            我們【g】繼續(xù)運(yùn)行,就會在 DoPrestub 方法斷住。我們在通過【!dumpmd】命令查看方法的描述符。

 1 0:000> g
 2 Breakpoint 0 hit
 3 eax=016c0470 ebx=00000000 ecx=6f08f6aa edx=01665384 esi=01703978 edi=01665384
 4 eip=6f08f78f esp=0133edf0 ebp=0133ee60 iopl=0         nv up ei pl zr na pe nc
 5 cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
 6 clr!PreStubWorker+0xe0:(斷點(diǎn)處)
 7 6f08f78f 8bf8            mov     edi,eax
 8 0:000> !dumpmd 01665384
 9 Method Name:  DynamicClass.Add(Int32, Int32)
10 Class:        016652f0
11 MethodTable:  01665344
12 mdToken:      06000000
13 Module:       01664eac
14 IsJitted:     yes
15 CodeAddr:     05940050(方法已經(jīng)編譯)
16 Transparency: Transparent

            我們有了CodeAddr: 05940050 方法的地址,我們就可以在這個(gè)地址上下斷點(diǎn)。

1 0:000> bp 05940050
2 0:000> g
3 Breakpoint 1 hit
4 eax=016c0470 ebx=0133ef84 ecx=0000000a edx=00000014 esi=033824c8 edi=0133eedc
5 eip=05940050 esp=0133ee88 ebp=0133eee8 iopl=0         nv up ei pl zr na pe nc
6 cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
7 05940050 8bc1            mov     eax,ecx

            我們下了斷點(diǎn),【g】繼續(xù)運(yùn)行。執(zhí)行進(jìn)入 Add 方法第一行就被斷住了,我們可以使用【!clrstack】命令,來驗(yàn)證。

1 0:000> !clrstack
2 OS Thread Id: 0x4168 (0)
3 Child SP       IP Call Site
4 0133ee88 05940050 DynamicClass.Add(Int32, Int32)(這就是我們動態(tài)生成的方法)
5 0133ee8c 016c0aab Example_10_1_1.Program.Main(System.String[]) [E:\Visual Studio 2022\Example_10_1_1\Program.cs @ 19]
6 0133f054 6efdf036 [GCFrame: 0133f054] 

           我們已經(jīng)成功命中了 Add 方法,還是挺不容易的。

1 0:000> !U /d 05940050
2 Normal JIT generated code
3 DynamicClass.Add(Int32, Int32)
4 Begin 05940050, size 5
5 >>> 05940050 8bc1            mov     eax,ecx
6 05940052 03c2            add     eax,edx
7 05940054 c3              ret

            ecx 是方法的第一個(gè)參數(shù),edx:是方法的第二個(gè)參數(shù)
            mov???? eax, ecx?? ?將 ecx 賦值給 eax,
            add???? eax, edx?? ?將 edx 和 eax 相加,eax 作為返回值返回
            ret
            我們對方法代碼也做了一些解釋。

        2.2、通過委托的函數(shù)指針找方法的描述符。
            測試源碼:Example_10_1_2
            我們通過 Windbg 直接加載 Example_10_1_2 項(xiàng)目,【g】命令直接運(yùn)行,會到【Debugger.Break()】這行代碼處暫停,也就是一個(gè) int 3 中斷。我們的程序輸出:Function Pointer:0x0000000004cd062e。然后我們使用【u 0x0000000004cd062e】命令,查看匯編代碼。

1 0:000> u 0x0000000004cd062e
2 04cd062e b81806cd04      mov     eax,4CD0618h
3 04cd0633 e9e4c9dbfb      jmp     00a8d01c
4 04cd0638 ab              stos    dword ptr es:[edi]
5 04cd0639 ab              stos    dword ptr es:[edi]
6 04cd063a ab              stos    dword ptr es:[edi]
7 04cd063b ab              stos    dword ptr es:[edi]
8 04cd063c ab              stos    dword ptr es:[edi]
9 04cd063d ab              stos    dword ptr es:[edi]

            4CD0618h 紅色標(biāo)注的就是包含方法描述符的地址。我們使用【dp 4CD0618h l1】命令,查看詳情。

1 0:000> dp 4CD0618h l1
2 04cd0618  00b20480

            00b20480 這個(gè)地址就是方法描述符,我們可以使用【!dumpmd 00b20480】命令。

0:000> dp 4CD0618h L1
04cd0618  00b20480
0:000> !U 00b20480
Unmanaged code
00b20480 e88bec4b6e      call    clr!PrecodeFixupThunk (6efdf110)
00b20485 5e              pop     esi
00b20486 001b            add     byte ptr [ebx],bl
00b20488 e883ec4b6e      call    clr!PrecodeFixupThunk (6efdf110)
00b2048d 5e              pop     esi
00b2048e 091a            or      dword ptr [edx],ebx
00b20490 e87bec4b6e      call    clr!PrecodeFixupThunk (6efdf110)
00b20495 5e              pop     esi
00b20496 1219            adc     bl,byte ptr [ecx]
00b20498 e873ec4b6e      call    clr!PrecodeFixupThunk (6efdf110)

            我這里沒有得到 Add 的方法描述符。沒有實(shí)現(xiàn)。

            
        2.3、在動態(tài)代碼中注入 Debugger.Break()實(shí)現(xiàn)代碼的調(diào)試。
            測試源碼:Example_10_1_3
            我們通過 windbg 正常加載項(xiàng)目,直接【g】運(yùn)行,會在16行處暫停,如圖:
            Net 高級調(diào)試之十:輕量級代碼生成的調(diào)試

             執(zhí)行效果如下:

1 0:000> !clrstack
2 OS Thread Id: 0x482c (0)
3 Child SP       IP Call Site
4 00b5f3a8 760df262 [HelperMethodFrame: 00b5f3a8] System.Diagnostics.Debugger.BreakInternal()
5 00b5f424 6e74f195 System.Diagnostics.Debugger.Break() [f:\dd\ndp\clr\src\BCL\system\diagnostics\debugger.cs @ 91]
6 00b5f44c 00f10053 DynamicClass.Add(Int32, Int32)
7 00b5f458 00ee0b56 Example_10_1_3.Program.Main(System.String[]) [E:\Visual Studio 2022\...\Example_10_1_3\Program.cs @ 24]
8 00b5f654 6efdf036 [GCFrame: 00b5f654] 

            00f10053 紅色標(biāo)注的就是我們要找的Add 方法。我們可以使用【!u】命令查看它的匯編代碼。

 1 0:000> !U /d 00f10053
 2 Normal JIT generated code
 3 DynamicClass.Add(Int32, Int32)
 4 Begin 00f10048, size 12
 5 00f10048 57              push    edi
 6 00f10049 56              push    esi
 7 00f1004a 8bf9            mov     edi,ecx
 8 00f1004c 8bf2            mov     esi,edx
 9 00f1004e e8e5f0836d      call    mscorlib_ni!System.Diagnostics.Debugger.Break (6e74f138)
10 >>> 00f10053 03fe            add     edi,esi
11 00f10055 8bc7            mov     eax,edi
12 00f10057 5e              pop     esi
13 00f10058 5f              pop     edi
14 00f10059 c3              ret


        2.4、程序集泄露
            測試源碼:Example_10_1_4
            我們加載完 Example_10_1_4 項(xiàng)目,【g】繼續(xù)運(yùn)行,運(yùn)行一段時(shí)間,我們點(diǎn)擊【break】按鈕暫停,當(dāng)然,在運(yùn)行的時(shí)候,我們可以通過任務(wù)管理器,查看這個(gè)應(yīng)用程序的內(nèi)存,發(fā)現(xiàn)內(nèi)存一直在增長。
            我們使用【!dumpdomain】命令,查看一下應(yīng)用程序域,不看不知道,一看嚇一跳。

 1 0:006> !dumpdomain
 2 --------------------------------------
 3 System Domain:      6f71caf8
 4 LowFrequencyHeap:   6f71ce1c
 5 HighFrequencyHeap:  6f71ce68
 6 StubHeap:           6f71ceb4
 7 Stage:              OPEN
 8 Name:               None
 9 --------------------------------------
10 Shared Domain:      6f71c7a8
11 LowFrequencyHeap:   6f71ce1c
12 HighFrequencyHeap:  6f71ce68
13 StubHeap:           6f71ceb4
14 Stage:              OPEN
15 Name:               None
16 Assembly:           00c9d6f8 [C:\Windows\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll]
17 ClassLoader:        00c9d7c0
18   Module Name
19 6dbc1000    C:\Windows\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
20 
21 --------------------------------------
22 Domain 1:           00c4d7c8
23 LowFrequencyHeap:   00c4dc34
24 HighFrequencyHeap:  00c4dc80
25 StubHeap:           00c4dccc
26 Stage:              OPEN
27 SecurityDescriptor: 00c4ece0
28 Name:               Example_10_1_4.exe
29 Assembly:           00c9d6f8 [C:\Windows\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll]
30 ClassLoader:        00c9d7c0
31 SecurityDescriptor: 00c9b0d0
32   Module Name
33 6dbc1000    C:\Windows\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
34 
35 Assembly:           00caa098 [E:\Visual Studio 2022\Source\Projects\Example_10_1_4.exe]
36 ClassLoader:        00ca7268
37 SecurityDescriptor: 00ca7160
38   Module Name
39 00c04044    E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\Example_10_1_4\bin\Debug\Example_10_1_4.exe
40 
41 Assembly:           00cab1c0 [C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Core\v4.0_4.0.0.0__b77a5c561934e089\System.Core.dll]
42 ClassLoader:        00cab288
43 SecurityDescriptor: 00ca88e0
44   Module Name
45 6c591000    C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Core\v4.0_4.0.0.0__b77a5c561934e089\System.Core.dll
46 
47 Assembly:           00caafc0 [C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System\v4.0_4.0.0.0__b77a5c561934e089\System.dll]
48 ClassLoader:        00ca9b18
49 SecurityDescriptor: 00cac6f0
50   Module Name
51 6d041000    C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System\v4.0_4.0.0.0__b77a5c561934e089\System.dll
52 
53 Assembly:           00cabee0 [C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Xml\v4.0_4.0.0.0__b77a5c561934e089\System.Xml.dll]
54 ClassLoader:        00cb3bd0
55 SecurityDescriptor: 00cabe48
56   Module Name
57 6bc01000    C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Xml\v4.0_4.0.0.0__b77a5c561934e089\System.Xml.dll
58 
59 Assembly:           00cb8b80 [C:\Windows\Microsoft.Net\assembly\\System.Configuration.dll]
60 ClassLoader:        00cb7538
61 SecurityDescriptor: 00cb8ae8
62   Module Name
63 6dab1000    C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Configuration\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Configuration.dll
64 
65 Assembly:           00cc3418 (Dynamic) []
66 ClassLoader:        00cc34e0
67 SecurityDescriptor: 00cc3380
68   Module Name
69 00c08b6c    Dynamic Module
70 
71 Assembly:           00cc8f58 (Dynamic) []
72 ClassLoader:        00cc9020
73 SecurityDescriptor: 00cc8ec0
74   Module Name
75 00c0954c    Dynamic Module
76 
77 Assembly:           00cd49e0 (Dynamic) []
78 ClassLoader:        00cd4aa8
79 SecurityDescriptor: 00cd4948
80   Module Name
81 00c09ce4    Dynamic Module
82 
83 ......(我清理了大量的動態(tài)模塊,顯示太多了)

            我們查看一下模塊的方法表,使用【!dumpmodule -mt】命令。

 1 0:006> !dumpmodule -mt 09e65b2c
 2 Name:       Unknown Module
 3 Attributes: Reflection 
 4 Assembly:   097f86c0
 5 LoaderHeap:              00000000
 6 TypeDefToMethodTableMap: 09e8195c
 7 TypeRefToMethodTableMap: 09e81970
 8 MethodDefToDescMap:      09e81984
 9 FieldDefToDescMap:       09e819ac
10 MemberRefToDescMap:      00000000
11 FileReferencesMap:       09e819fc
12 AssemblyReferencesMap:   09e81a10
13 
14 Types defined in this module
15 
16       MT  TypeDef Name
17 ------------------------------------------------------------------------------
18 09e65f68 0x02000002 <Unloaded Type>
19 09e6605c 0x02000003 <Unloaded Type>
20 09e660e4 0x02000004 <Unloaded Type>
21 09e66184 0x02000005 <Unloaded Type>
22 09e66260 0x02000006 <Unloaded Type>
23 
24 Types referenced in this module
25 
26       MT    TypeRef Name
27 ------------------------------------------------------------------------------

            我們查找紅色標(biāo)記 09e65f68 方法表的所有方法描述符。

 1 0:006> !dumpmt -md 09e65f68
 2 EEClass:         09e82bf8
 3 Module:          09e65b2c
 4 Name:            <Unloaded Type>
 5 mdToken:         02000002
 6 File:            Unknown Module
 7 BaseSize:        0x44
 8 ComponentSize:   0x0
 9 Slots in VTable: 8
10 Number of IFaces in IFaceMap: 0
11 --------------------------------------
12 MethodDesc Table
13    Entry MethodDe    JIT Name
14 6dfc97b8 6dbcc838 PreJIT System.Object.ToString()
15 6dfc96a0 6dd08978 PreJIT System.Object.Equals(System.Object)
16 6dfd21f0 6dd08998 PreJIT System.Object.GetHashCode()
17 6df84f2c 6dd089a0 PreJIT System.Object.Finalize()
18 09e4a47d 09e65f44   NONE Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterCustomer.InitCallbacks()
19 09e4a481 09e65f4c   NONE Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterCustomer..ctor()
20 09e4a475 09e65f2c   NONE Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterCustomer.Write3_FabrikamCustomer(...)
21 09e4a479 09e65f38   NONE Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterCustomer.Write2_Customer(... Boolean)

            這里大量的有?Serialization.GeneratedAssembly 這個(gè)方法,估計(jì)判斷是程序集泄露。既然這么多程序集產(chǎn)生,應(yīng)該就有一個(gè)創(chuàng)建程集的方法,我們使用【x】命令,查找一下。

1 0:006> x clr!*CreateDynamic*
2 6f385b06          clr!Assembly::CreateDynamicModule (public: class ReflectionModule * __thiscall Assembly::CreateDynamicModule(unsigned short const *,unsigned short const *,int,int *))
3 6f5b0aff          clr!HENUMInternal::CreateDynamicArrayEnum (public: static long __stdcall HENUMInternal::CreateDynamicArrayEnum(unsigned long,struct HENUMInternal * *))
4 6f166b49          clr!Assembly::CreateDynamic (public: static class Assembly * __stdcall Assembly::CreateDynamic(class AppDomain *,struct CreateDynamicAssemblyArgs *))
5 6f167440          clr!AppDomainNative::CreateDynamicAssembly (public: static class Object * __fastcall AppDomainNative::CreateDynamicAssembly(class AppDomainBaseObject *,class AssemblyNameBaseObject *,enum SecurityContextSource,int,int,class Array<unsigned char> *,class Array<unsigned char> *,class Object *,class Object *,class Object *,enum StackCrawlMark *,class Object *))
6 6f3dd86f          clr!DynamicMethodTable::CreateDynamicMethodTable (public: static void __stdcall DynamicMethodTable::CreateDynamicMethodTable(class DynamicMethodTable * *,class Module *,class AppDomain *))

            就是這個(gè)方法創(chuàng)建程序集,我們可以對這個(gè)方法下一個(gè)斷點(diǎn)。

1 0:006> bp clr!Assembly::CreateDynamic

            【g】繼續(xù)運(yùn)行,在 CreateDynamic 方法內(nèi)暫停。

1 0:006> g
2 Breakpoint 0 hit
3 eax=00c4d7c8 ebx=00000000 ecx=00c4d7c8 edx=008fecb4 esi=02ad7a5c edi=00000000
4 eip=6f166b49 esp=008fec3c ebp=008fed00 iopl=0         nv up ei pl nz na po nc
5 cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000202
6 clr!Assembly::CreateDynamic:(成功斷?。?7 6f166b49 6814070000      push    714h

            然后我們使用【k】命令,查看是誰調(diào)用了這個(gè)函數(shù)。

 1 0:000> k
 2 *** WARNING: Unable to verify checksum for C:\Windows\assembly\NativeImages_v4.0.30319_32\System.Xml\040fa6ee0be6d987f3e8edf9010ce68a\System.Xml.ni.dll
 3 *** WARNING: Unable to verify checksum for C:\Windows\assembly\NativeImages_v4.0.30319_32\System.Core\44e36f78b5e2f34aba2d7b5667796954\System.Core.ni.dll
 4  # ChildEBP RetAddr      
 5 00 010feef0 6f167543     clr!Assembly::CreateDynamic
 6 01 010feef0 6dfef391     clr!AppDomainNative::CreateDynamicAssembly+0xdf
 7 02 010fef78 6dfef261     mscorlib_ni!System.Reflection.Emit.AssemblyBuilder..ctor+0xed [f:\dd\ndp\clr\src\BCL\system\reflection\emit\assemblybuilder.cs @ 424] 
 8 03 010fefd4 6e016558     mscorlib_ni!System.Reflection.Emit.AssemblyBuilder.InternalDefineDynamicAssembly+0x89 [f:\dd\ndp\clr\src\BCL\system\reflection\emit\assemblybuilder.cs @ 569] 
 9 04 010feffc 6e016527     mscorlib_ni!System.AppDomain.InternalDefineDynamicAssembly+0x28 [f:\dd\ndp\clr\src\BCL\system\appdomain.cs @ 1515] 
10 05 010ff02c 6bd100bd     mscorlib_ni!System.AppDomain.DefineDynamicAssembly+0x2b [f:\dd\ndp\clr\src\BCL\system\appdomain.cs @ 1221] 
11 06 010ff044 6bd0fa1b     System_Xml_ni!System.Xml.Serialization.CodeGenerator.CreateAssemblyBuilder+0x8d
12 07 010ff0dc 6bd0f696     System_Xml_ni!System.Xml.Serialization.TempAssembly.GenerateRefEmitAssembly+0xcf
13 08 010ff110 6c09db2a     System_Xml_ni!System.Xml.Serialization.TempAssembly..ctor+0xae
14 09 010ff138 6c09da72     System_Xml_ni!System.Xml.Serialization.XmlSerializer.GenerateTempAssembly+0x6a
15 0a 010ff164 6c09d8e7     System_Xml_ni!System.Xml.Serialization.XmlSerializer..ctor+0xd2
16 0b 010ff18c 017710aa     System_Xml_ni!System.Xml.Serialization.XmlSerializer..ctor+0x2f
17 WARNING: Frame IP not in any known module. Following frames may be wrong.
18 0c 010ff1e8 01770ffc     0x17710aa
19 0d 010ff200 01770f88     0x1770ffc
20 0e 010ff210 6dfaaa67     0x1770f88
21 0f 010ff244 6c77c5de     mscorlib_ni!System.Collections.Generic.List`1..ctor+0xf7 [f:\dd\ndp\clr\src\BCL\system\collections\generic\list.cs @ 99] 
22 10 010ff258 017708f2     System_Core_ni+0x1ec5de
23 11 010ff288 6efdf036     0x17708f2
24 12 010ff294 6efe22da     clr!CallDescrWorkerInternal+0x34
25 13 010ff2e8 6efe859b     clr!CallDescrWorkerWithHandler+0x6b
26 14 010ff354 6f18b11b     clr!MethodDescCallSite::CallTargetWorker+0x16a
27 15 010ff478 6f18b7fa     clr!RunMain+0x1b3
28 16 010ff6e4 6f18b727     clr!Assembly::ExecuteMainMethod+0xf7
29 17 010ffbc8 6f18b8a8     clr!SystemDomain::ExecuteMainMethod+0x5ef
30 18 010ffc20 6f18b9ce     clr!ExecuteEXE+0x4c
31 19 010ffc60 6f187305     clr!_CorExeMainInternal+0xdc
32 1a 010ffc9c 721bfa84     clr!_CorExeMain+0x4d
33 1b 010ffcd4 7224e81e     mscoreei!_CorExeMain+0xd6
34 1c 010ffce4 72254338     MSCOREE!ShellShim__CorExeMain+0x9e
35 1d 010ffcfc 765ff989     MSCOREE!_CorExeMain_Exported+0x8
36 1e 010ffcfc 77b27084     KERNEL32!BaseThreadInitThunk+0x19
37 1f 010ffd58 77b27054     ntdll!__RtlUserThreadStart+0x2f
38 20 010ffd68 00000000     ntdll!_RtlUserThreadStart+0x1b

            或者我們使用【!clrstack】命令,查看一下調(diào)用堆棧,這個(gè)命令看的更清楚。

 1 0:000> !clrstack
 2 OS Thread Id: 0x3534 (0)
 3 Child SP       IP Call Site
 4 010fee44 6f166b49 [HelperMethodFrame_PROTECTOBJ: 010fee44] System.Reflection.Emit.AssemblyBuilder.nCreateDynamicAssembly(System.AppDomain, System.Reflection.AssemblyName, System.Security.Policy.Evidence, System.Threading.StackCrawlMark ByRef, System.Security.PermissionSet, System.Security.PermissionSet, System.Security.PermissionSet, Byte[], Byte[], System.Reflection.Emit.AssemblyBuilderAccess, System.Reflection.Emit.DynamicAssemblyFlags, System.Security.SecurityContextSource)
 5 010fef20 6dfef391 System.Reflection.Emit.AssemblyBuilder..ctor(System.AppDomain, System.Reflection.AssemblyName, System.Reflection.Emit.AssemblyBuilderAccess, System.String, System.Security.Policy.Evidence, System.Security.PermissionSet, System.Security.PermissionSet, System.Security.PermissionSet, System.Threading.StackCrawlMark ByRef, System.Collections.Generic.IEnumerable`1<System.Reflection.Emit.CustomAttributeBuilder>, System.Security.SecurityContextSource) [f:\dd\ndp\clr\src\BCL\system\reflection\emit\assemblybuilder.cs @ 424]
 6 010fefa8 6dfef261 System.Reflection.Emit.AssemblyBuilder.InternalDefineDynamicAssembly(System.Reflection.AssemblyName, System.Reflection.Emit.AssemblyBuilderAccess, System.String, System.Security.Policy.Evidence, System.Security.PermissionSet, System.Security.PermissionSet, System.Security.PermissionSet, System.Threading.StackCrawlMark ByRef, System.Collections.Generic.IEnumerable`1<System.Reflection.Emit.CustomAttributeBuilder>, System.Security.SecurityContextSource) [f:\dd\ndp\clr\src\BCL\system\reflection\emit\assemblybuilder.cs @ 569]
 7 010feffc 6e016558 System.AppDomain.InternalDefineDynamicAssembly(System.Reflection.AssemblyName, System.Reflection.Emit.AssemblyBuilderAccess, System.String, System.Security.Policy.Evidence, System.Security.PermissionSet, System.Security.PermissionSet, System.Security.PermissionSet, System.Threading.StackCrawlMark ByRef, System.Collections.Generic.IEnumerable`1<System.Reflection.Emit.CustomAttributeBuilder>, System.Security.SecurityContextSource) [f:\dd\ndp\clr\src\BCL\system\appdomain.cs @ 1515]
 8 010ff028 6e016527 System.AppDomain.DefineDynamicAssembly(System.Reflection.AssemblyName, System.Reflection.Emit.AssemblyBuilderAccess) [f:\dd\ndp\clr\src\BCL\system\appdomain.cs @ 1221]
 9 010ff038 6bd100bd System.Xml.Serialization.CodeGenerator.CreateAssemblyBuilder(System.AppDomain, System.String)
10 010ff04c 6bd0fa1b System.Xml.Serialization.TempAssembly.GenerateRefEmitAssembly(System.Xml.Serialization.XmlMapping[], System.Type[], System.String, System.Security.Policy.Evidence)
11 010ff0ec 6bd0f696 System.Xml.Serialization.TempAssembly..ctor(System.Xml.Serialization.XmlMapping[], System.Type[], System.String, System.String, System.Security.Policy.Evidence)
12 010ff128 6c09db2a System.Xml.Serialization.XmlSerializer.GenerateTempAssembly(System.Xml.Serialization.XmlMapping, System.Type, System.String, System.String, System.Security.Policy.Evidence)
13 010ff14c 6c09da72 System.Xml.Serialization.XmlSerializer..ctor(System.Type, System.Xml.Serialization.XmlAttributeOverrides, System.Type[], System.Xml.Serialization.XmlRootAttribute, System.String, System.String, System.Security.Policy.Evidence)
14 010ff184 6c09d8e7 System.Xml.Serialization.XmlSerializer..ctor(System.Type, System.Xml.Serialization.XmlRootAttribute)
15 010ff198 017710aa Example_10_1_4.Program.GetCustomer(Int32, System.String, System.String) [E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\Example_10_1_4\Program.cs @ 27]
16 010ff1f4 01770ffc Example_10_1_4.Program+c__DisplayClass0_0.b__0(Int32) [E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\Example_10_1_4\Program.cs @ 18]
17 010ff208 01770f88 System.Linq.Enumerable+WhereSelectEnumerableIterator`2[[System.Int32, mscorlib],[System.__Canon, mscorlib]].MoveNext()
18 010ff218 6dfaaa67 System.Collections.Generic.List`1[[System.__Canon, mscorlib]]..ctor(System.Collections.Generic.IEnumerable`1<System.__Canon>) [f:\dd\ndp\clr\src\BCL\system\collections\generic\list.cs @ 99]
19 010ff24c 6c77c5de System.Linq.Enumerable.ToList[[System.__Canon, mscorlib]](System.Collections.Generic.IEnumerable`1<System.__Canon>)
20 010ff260 017708f2 Example_10_1_4.Program.Main(System.String[]) [E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\Example_10_1_4\Program.cs @ 17]
21 010ff3f8 6efdf036 [GCFrame: 010ff3f8] 

              我們終于找到問題了。代碼中把解決辦法已經(jīng)寫好了。


四、總結(jié)
    終于寫完了,寫作的過程是累并快樂著。學(xué)習(xí)過程真的沒那么輕松,還好是自己比較喜歡這一行,否則真不知道自己能不能堅(jiān)持下來。老話重談,《高級調(diào)試》的這本書第一遍看,真的很暈,第二遍稍微好點(diǎn),不學(xué)不知道,一學(xué)嚇一跳,自己欠缺的很多。好了,不說了,不忘初心,繼續(xù)努力,希望老天不要辜負(fù)努力的人。文章來源地址http://www.zghlxwxcb.cn/news/detail-747051.html

到了這里,關(guān)于Net 高級調(diào)試之十:輕量級代碼生成的調(diào)試的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 『SEQ日志』在 .NET中快速集成輕量級的分布式日志平臺

    『SEQ日志』在 .NET中快速集成輕量級的分布式日志平臺

    ??讀完這篇文章里你能收獲到 如何在Docker中部署 SEQ:介紹了如何創(chuàng)建和運(yùn)行 SEQ 容器,給出了詳細(xì)的執(zhí)行操作 如何使用 NLog 接入 .NET Core 應(yīng)用程序的日志:詳細(xì)介紹了 NLog 和 NLog.Seq 來配置和記錄日志的步驟 日志記錄示例:博客提供了一個(gè)簡單的日志記錄示例,展示了如何在

    2024年02月11日
    瀏覽(102)
  • 尚硅谷Docker實(shí)戰(zhàn)教程-筆記13【高級篇,Docker輕量級可視化工具Portainer】

    尚硅谷Docker實(shí)戰(zhàn)教程-筆記13【高級篇,Docker輕量級可視化工具Portainer】

    尚硅谷大數(shù)據(jù)技術(shù)-教程-學(xué)習(xí)路線-筆記匯總表【課程資料下載】 視頻地址:尚硅谷Docker實(shí)戰(zhàn)教程(docker教程天花板)_嗶哩嗶哩_bilibili 尚硅谷Docker實(shí)戰(zhàn)教程-筆記01【基礎(chǔ)篇,Docker理念簡介、官網(wǎng)介紹、平臺入門圖解、平臺架構(gòu)圖解】 尚硅谷Docker實(shí)戰(zhàn)教程-筆記02【基礎(chǔ)篇,Do

    2024年02月15日
    瀏覽(118)
  • Net 高級調(diào)試之十一:托管堆布局架構(gòu)和對象分配機(jī)制

    Net 高級調(diào)試之十一:托管堆布局架構(gòu)和對象分配機(jī)制

    一、簡介 今天是《Net 高級調(diào)試》的第十一篇文章,這篇文章來的有點(diǎn)晚,因?yàn)?,最近比較忙,就沒時(shí)間寫文章了?,F(xiàn)在終于有點(diǎn)時(shí)間,繼續(xù)開始我們這個(gè)系列。這篇文章我們主要介紹托管堆的架構(gòu),對象的分配機(jī)制,我們?nèi)绾尾檎以谕泄芏焉系膶ο螅覍W(xué)完這章,很多以前

    2024年02月05日
    瀏覽(19)
  • C#輕量級高并發(fā)物聯(lián)網(wǎng)服務(wù)器接收程序源碼,可對接數(shù)萬設(shè)備,數(shù)據(jù)庫可自行選擇(EF6+SQLite或EF+MySQL),適合中高級開發(fā)者使用

    C#輕量級高并發(fā)物聯(lián)網(wǎng)服務(wù)器接收程序源碼,可對接數(shù)萬設(shè)備,數(shù)據(jù)庫可自行選擇(EF6+SQLite或EF+MySQL),適合中高級開發(fā)者使用

    c#輕量級高并發(fā)物聯(lián)網(wǎng)服務(wù)器接收程序源碼(僅僅是接收硬件數(shù)據(jù)程序,沒有web端,不是java,協(xié)議自己寫,如果問及這些問題統(tǒng)統(tǒng)不回復(fù)。 ),對接幾萬個(gè)設(shè)備沒問題,數(shù)據(jù)庫采用ef6+sqlite,可改ef+MySQL.該程序只是源碼使用示例,里面有使用方法,自己研究,難度屬中上層不

    2024年04月11日
    瀏覽(96)
  • git輕量級服務(wù)器gogs、gitea,非輕量級gitbucket

    git輕量級服務(wù)器gogs、gitea,非輕量級gitbucket

    本文來源:git輕量級服務(wù)器gogs、gitea,非輕量級gitbucket, 或 gitcode/gogs,gitea.md 結(jié)論: gogs、gitea很相似 確實(shí)輕, gitbucket基于java 不輕, 這三者都不支持組織樹(嵌套組織 nested group) 只能一層組織。 個(gè)人用,基于gogs、gitea,兩層結(jié)構(gòu)樹 簡易辦法: 把用戶當(dāng)成第一層節(jié)點(diǎn)、該用戶的

    2024年02月07日
    瀏覽(140)
  • 輕量靈動: 革新輕量級服務(wù)開發(fā)

    輕量靈動: 革新輕量級服務(wù)開發(fā)

    從 JDK 8 升級到 JDK 17 可以讓你的應(yīng)用程序受益于新的功能、性能改進(jìn)和安全增強(qiáng)。下面是一些 JDK 8 升級到 JDK 17 的最佳實(shí)戰(zhàn): 1.1、確定升級的必要性:首先,你需要評估你的應(yīng)用程序是否需要升級到 JDK 17。查看 JDK 17 的新特性、改進(jìn)和修復(fù)的 bug,以確定它們對你的應(yīng)用程序

    2024年02月07日
    瀏覽(99)
  • 輕量級 HTTP 請求組件

    Apache HttpClient 是著名的 HTTP 客戶端請求工具——現(xiàn)在我們模擬它打造一套簡單小巧的請求工具庫, 封裝 Java 類庫里面的 HttpURLConnection 對象來完成日常的 HTTP 請求,諸如 GET、HEAD、POST 等等,并嘗試應(yīng)用 Java 8 函數(shù)式風(fēng)格來制定 API。 組件源碼在:https://gitee.com/sp42_admin/ajaxjs/tr

    2024年02月01日
    瀏覽(101)
  • Kotlin 輕量級Android開發(fā)

    Kotlin 輕量級Android開發(fā)

    Kotlin 是一門運(yùn)行在 JVM 之上的語言。 它由 Jetbrains 創(chuàng)建,而 Jetbrains 則是諸多強(qiáng)大的工具(如知名的 Java IDE IntelliJ IDEA )背后的公司。 Kotlin 是一門非常簡單的語言,其主要目標(biāo)之一就是提供強(qiáng)大語言的同時(shí)又保持簡單且精簡的語法。 其主要特性如下所示: 輕量級:這一點(diǎn)對

    2024年02月07日
    瀏覽(904)
  • Tomcat輕量級服務(wù)器

    Tomcat輕量級服務(wù)器

    目錄 1.常見系統(tǒng)架構(gòu)? C-S架構(gòu) B-S架構(gòu) 2.B-S架構(gòu)系統(tǒng)的通信步驟 3.常見WEB服服務(wù)器軟件 4.Tomcat服務(wù)器的配置 下載安裝 環(huán)境變量配置 測試環(huán)境變量是否配置成功 測試Tomcat服務(wù)器是否配置成功? Tomcat窗口一閃而過的解決步驟 Tomcat解決亂碼 介紹: C-S架構(gòu)即Client/Server(客戶端/服務(wù)

    2023年04月14日
    瀏覽(103)
  • 一種輕量級定時(shí)任務(wù)實(shí)現(xiàn)

    現(xiàn)在市面上有各式各樣的分布式定時(shí)任務(wù),每個(gè)都有其獨(dú)特的特點(diǎn),我們這邊的項(xiàng)目因?yàn)橐婚_始使用的是分布式開源調(diào)度框架TBSchedule,但是這個(gè)框架依賴ZK, 由于ZK的不穩(wěn)定性和項(xiàng)目老舊無人維護(hù) ,導(dǎo)致我們的定時(shí)任務(wù)會偶發(fā)出現(xiàn)異常,比如:任務(wù)停止、任務(wù)項(xiàng)丟失、任務(wù)不

    2024年02月14日
    瀏覽(96)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包