WinDbg調試C#技巧,解決CPU過高、死鎖、內存爆滿


軟件安裝

安裝問題:執行 .loadby sos clr 命令無效

解決辦法:

.load C:\Windows\Microsoft.NET\Framework64\v4.0.30319\SOS.dll
.load C:\Windows\Microsoft.NET\Framework64\v4.0.30319\clr.dll
.loadby sos clr

代碼調試

查看線程

命令: !threads 

執行結果:

進入線程

命令: ~~[線程Id]s 

執行結果:

查看線程詳情

命令: !clrstack 

執行結果:

查看線程狀態

命令:  !ThreadState 線程StateId 

執行結果:

 

退出附加進程

命令: qd 

查看線程環境塊(空間)

命令:  !Teb 

執行結果:

查看線程堆棧

命令:  !dumpstack 

執行結果:

查看局部變量

命令:  !clrstack 

    !clrstack -l 

執行結果:

查看幫助

命令:   !help 

執行結果:

 

查看終結器隊列

命令:  !FinalizeQueue 

執行結果:

 

查看線程池詳情

命令: !threadpool 

執行結果:

 

查看查看當前托管線程已執行時間

命令:  !runaway 

執行結果:

清屏

命令:  !cls 

查看查看當前托管線程已執行時間

命令:  ~*e!clrstack 

執行結果:看所有線程的堆棧

 

CPU過高的問題

模擬CPU過高

示例代碼:

class Program
{
    static void Main(string[] args)
    {
        Run();

        Console.Read();
    }

    static void Run()
    {
        var task = Task.Factory.StartNew(() =>
        {
            //這是一個非常復雜的邏輯,導致死循環
            while (true)
            {

            }
        });
    }
}

生成64位Realease版本代碼:

在Bin/Realse下找到文件並運行,然后查看CPU:

解決CUP占用過高

創建轉儲文件:

↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓

找到該轉儲文件:C:\Users\ADMINI~1\AppData\Local\Temp\ConsoleApp4.DMP

用X64版本的WinDbg打開DMP文件:

↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓

然后打開命令輸入:

然后輸入 .loadby sos clr 與 !threads 

現在線程少沒有關系,多的話我們沒有辦法去判斷哪個線程消耗嚴重,所以執行 !runaway 查看當前托管線程已執行時間

切換到指定線程 ~~[4f78]s ,執行  !clrstack  查看當前線程的調用堆棧

從調用堆棧上來看,當前線程 在 Program+c.b__1_0() 方法之后23行就沒有調用堆棧了,說明方法在這個地方停滯不前了。

最后反編譯源碼到指定的方法中去查看

方法二:

通過 !dumpdomain 拿到程序地址

然后反編譯成dll輸出文件 !savemodule 00007ff7e4f94120 c:\2\1.dll (文件夾必須存在)

然后找到該dll進行反編譯

死鎖問題

模擬死鎖

實例代碼:

class Program
{
    static void Main(string[] args)
    {
        new Program().Run();

        Console.Read();
    }

    void Run()
    {
        lock (this)
        {
            var task = Task.Factory.StartNew(() =>
            {
                Console.WriteLine("-------start-------");
                Thread.Sleep(1000);

                Run2();
                Console.WriteLine("---------end--------");
            });

            task.Wait();
        }
    }

    void Run2()
    {
        lock (this)
        {
            Console.WriteLine("------我是Run2------");
        }
    }
}

執行結果:

解決死鎖

然后用WinDbg附加到進程,執行 .loadby sos clr 與 !threads 查看當前的托管線程

 

然后執行 ~*e!clrstack 查看所有線程的堆棧

可以看出主線程在等待

執行 !syncblk 查看當前哪個線程持有鎖,可以看出主線程持有鎖

可以看得出“主線程”持有當前的同步鎖

內存爆滿

模擬內存爆滿

實例代碼:

class Program
{
    static StringBuilder sb = new StringBuilder();
    static void Main(string[] args)
    {
        for (int i = 0; i < 10000000; i++)
        {
            sb.Append("hello world");
        }

        Console.WriteLine("執行完畢");
        Console.Read();
    }
}

解決內存爆滿

然后用WinDbg附加到進程,執行  .loadby sos clr 與  !threads ,然后執行  !dumpheap -stat 查看clr的托管堆中的各個類型的占用情況

然后看到了有13768個char[]數組

然后執行 !DumpHeap /d -mt 00007ff841318610    //查看當前的方法表

然后執行 !DumpObj /d 0000022baed1dec8 //查看當前char[]的內容

然后執行 !gcroot 00000135a60f4940 查看當前地址的Root。。。

 

所以結合“StringBuilder”,結合 ”hello world“ 我們就找出了問題。。。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM