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

軟件安裝

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

解決辦法:dom

.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 ui

執行結果:

this

進入線程

命令: ~~[線程Id]s spa

執行結果:
線程

查看線程詳情

命令: !clrstack 3d

執行結果:調試

查看線程狀態

命令:  !ThreadState 線程StateId code

執行結果:blog

 

退出附加進程

命令: 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「 咱們就找出了問題。。。

相關文章
相關標籤/搜索