[ASP.NET Debugging BuggyBits读书笔记] Lab04 High CP...

1. 在IIS里访问AllProducts.aspx启动w3wp.exe进程。 oop

2. 使用TinyGet执行 tinyget srv:localhost –uri:/buggybits/AllProducts.aspx –threads:5 –loop:1 ui

3. 在WinDbg目录执行 adplus –hang –pn w3wp.exe –quiet 线程

4. 使用WinDbg打开第三步生成的.dmp文件,执行 .loadby sos.dll mscorwks orm

5. 执行 !threadpool 查看当前生成dmp时的CPU利用率 : 对象

image

可见当前CPU利用率为100% blog

6. 执行 !runaway查看没有线程占用的CPU时间: 进程

image

可见占用CPU时间最多的是线程18。 字符串

7. 切换到该线程,执行~18s。而后执行 !clrstack 查看该线程执行到了什么地方: get

image

可见程序在Page_load方法里卡住了。找到这条指令所在地址 075f09c9 string

8. 执行 !u 075f09c9进行反汇编:

image

怀疑程序是在进行字符串构造。

9. 执行 !dso 查看该线程相关的object,找到大量的字符串对象。

10. 查看程序源代码AllProducts.aspx.cs:

image

可见程序直接使用了 + 进行字符串链接。这正好与System.String.Concat方法契合。

因为直接将字符串进行相连,会致使以前分配字符串对象的存储空间被废弃,CLR必须为新的字符串对象分配新的空间,这就致使CLR忙于分配字符串空间,形成high CPU。好比下例:

class Program 

    static void Main(string[] args) 
    { 
        string s = null; 
        for (int i = 0; i < 100000; i++) 
        { 
            s = s + i.ToString(); 
        } 
    } 

运行以后能够直接在Task Manager里看到CPU占用率的直线上升。

对此的解决办法是使用StringBuilder:

class Program 

    static void Main(string[] args) 
    { 
        StringBuilder sb = new StringBuilder(); 
        for (int i = 0; i < 100000; i++) 
        { 
            sb.Append(i.ToString()); 
        } 
    } 
}

这样当有新的String声称以后,旧有的string会在原对象大小的基础分配一个大小为原对象大小两倍的对象。这样就避免CLR反复消耗于分配新的对象。

20110218更新:

1、 若是怀疑是High CPU,则使用!threadpool查看究竟多高,再使用!runaway查看哪一个thread占用的CPU最高,第三步使用!threads查看各个托管thread的类型。

2、使用Performance Monitor的.CLR Memory对象和Process对象,进行监测,查看的counter包括#Gen 0/1/2 collections,Induced GC,Processor Time和Time in GC。获得以下图像:

  

  1. 从Processor Time能够看到CPU利用率获得100%,而从%Time in GC(途中白色部分)能够得知GC垃圾回收过程占用了大部分的CPU使用。GC的平均利用率在65%,可是正常状况下应该不会超过5%。

  2. Gen 0/1/2 Collections的数量基本相等,比值约为1:1:1;可是正常状况下,其比值应约为100:10:1。

  3. 致使Gen 0/1/2 Collections对象数量近似的缘由只有一个,那就是GC回收过程被反复触发。其中触发有两种状况,一种是手动执行GC回收,另一种是在Gen0中的对象太大,致使Gen0空间很快不足,GC被触发,成了Gen1,而Gen1很快又给弄成了Gen2,因此三代对象基本相等。

  4. 从Induced GC能够得知并无手动触发存在,从而断定是Object太大。

3、切换到CPU占用率高的线程,执行!clrstack,发现该线程在作以下工做:

  0:016> !clrstack
OS Thread Id: 0x1948 (16)
ESP       EIP     
0252f208 7d61c828 [RedirectedThreadFrame: 0252f208] 
0252f24c 79363058 System.String.wstrcpy(Char*, Char*, Int32)
0252f258 7936d6e7 System.String.FillStringChecked(System.String, Int32, System.String)
0252f278 79378b9f System.String.ConcatArray(System.String[], Int32)
0252f28c 79378af4 System.String.Concat(System.Object[])
0252f2a0 0fe90a2a AllProducts.Page_Load(System.Object, System.EventArgs)
0252f2d8 66f12980 System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr, System.Object, System.Object, System.EventArgs)
0252f2e8 6628efd2 System.Web.Util.CalliEventHandlerDelegateProxy.Callback(System.Object, System.EventArgs)
0252f2f8 6613cb04 System.Web.UI.Control.OnLoad(System.EventArgs)
0252f308 6613cb50 System.Web.UI.Control.LoadRecursive()
0252f31c 6614e12d System.Web.UI.Page.ProcessRequestMain(Boolean, Boolean)
0252f518 6614d8c3 System.Web.UI.Page.ProcessRequest(Boolean, Boolean)
0252f550 6614d80f System.Web.UI.Page.ProcessRequest()
0252f588 6614d72f System.Web.UI.Page.ProcessRequestWithNoAssert(System.Web.HttpContext)
0252f590 6614d6c2 System.Web.UI.Page.ProcessRequest(System.Web.HttpContext)
0252f5a4 0fe90205 ASP.allproducts_aspx.ProcessRequest(System.Web.HttpContext)
0252f5a8 65fe6bfb System.Web.HttpApplication+CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
0252f5dc 65fe3f51 System.Web.HttpApplication.ExecuteStep(IExecutionStep, Boolean ByRef)
0252f61c 65fe7733 System.Web.HttpApplication+ApplicationStepManager.ResumeSteps(System.Exception)
0252f66c 65fccbfe System.Web.HttpApplication.System.Web.IHttpAsyncHandler.BeginProcessRequest(System.Web.HttpContext, System.AsyncCallback, System.Object)
0252f688 65fd19c5 System.Web.HttpRuntime.ProcessRequestInternal(System.Web.HttpWorkerRequest)
0252f6bc 65fd16b2 System.Web.HttpRuntime.ProcessRequestNoDemand(System.Web.HttpWorkerRequest)
0252f6c8 65fcfa6d System.Web.Hosting.ISAPIRuntime.ProcessRequest(IntPtr, Int32)
0252f8d8 79f047fd [ContextTransitionFrame: 0252f8d8] 
0252f90c 79f047fd [GCFrame: 0252f90c] 
0252fa68 79f047fd [ComMethodFrame: 0252fa68]

于是怀疑这个巨大的object是System.String类型。

  执行命令 !dumpheap -type System.String -min 85000:

找到heap中相关的string对象,经过!do查看其内容,即可得知程序是在构造一个超长的字符串。

相关文章
相关标签/搜索