(翻译)How To: Use CLR Profiler
第一次翻译对我而言比较长的E文,有很多不足之处,请见谅。(个人的习惯GC又做了名词又做了名词)
原文:http://msdn.microsoft.com/en-us/library/ms979205.aspx
概况
CLR Profiler 能让你观察一个进程托管堆和研究(investigate)垃圾回收机制的行为表现。使用该工具中不同的视图,你能获得关于你运用程序的执行,分配和内存消耗的有用信息。
CLR Profiler 不是一个分析问题的出发点。然而,它能帮助你验证和隔离问题代码并追踪内存泄漏。使用CLR Profiler,你能了解代码分配了多少内存,引起了多少垃圾回收和占用内存多久。
注:CLR Profiler 是一个使你的应用的执行比起正常情况下明显(significantly)慢(有的地方是10-100倍)的插入式(intrusive)工具。它的设计目的不是在产品环境下使用的。
你必须知道的
CLR Profiler的主要功能是让你明白你的应用在使用托管、GC堆时如何互相协作的(interact with).你能分析一些更为重要的信息:
*谁分配了一些什么在托管堆
*哪些对象在托管堆中存活(survive)了下来
*谁是对象的持有者
*GC在你的应用程序的生命周期中做了什么
分析的结构存放在日志文件中。你能通过CLR Profiler中的视图菜单查看这些文件以不同的方式,展现出对应的图表(corresponding graph)。表1列出了最为有用的视图。
表1:CLR Profiler视图
视图 |
描述 |
Histogram Allocated Types |
给你一个高等级的视图,它指出对象类型(分配的大小)在你的应用程序的生命周期内被分配的情况。这个视图也显示那些被分配在大对象堆(对象超过85KB)中的对象。 这个视图允许你点击图标的各个部分,为了你能看见哪些方法分配了哪些对象。 |
Histogram Relocated Types |
显示已被GC(重新)分配(位置)的对象,因为他们在一次GC后存活了下来(就是别人还引用他们) |
Objects By Address |
提供一个任意特定时间(at a given time)托管堆情况的图片 |
Allocation Graph |
用图表显示调用的堆栈是如何分别的对象。你能使用的视图有: *查看方法的分配成本(the cost of each alloction) *隔离你不期望的分配 *找出有可能过度分配的方法 |
Assemby,Module,Function,and Class Graph |
有4个非常相仿的视图。他们允许你看哪些方法涉及到了哪些程序集、类、模块、方法 |
Heap Graph |
显示托管堆上所有对象,以及他们的关联信息。 |
Call Graph |
使你查看哪些方法调用了哪些别的方法和多少频率。 你能使用这个图表摸索着了解类库的调用成本并判定调用这个方法的需求量和哪些方法被调用。 |
Time Line |
显示GC的在你的应用程序中的重新分配情况(就是那些么有被清楚的对象)。使用这个视图去: *研究了解GC的行为 *判定在3代中有多少GC发生(0,1,2代),和发生频率。 *判定哪些对象在GC后存活,被提升到了下一代。 你能选择时间点或间隔(intervals),通过右击去显示在这个时间间隙内(interval)谁分配了内存。 |
Call Tree View |
提供一个你应用程序执行的视图,它是基于文本按年代分级。使用这个视图可以: *查看什么类型被分配及他们的大小 *查看哪些程序集因方法调用而被被加载 *分析终结(finalizer)的使用,和他们的执行次数 *识别(indentify)方法在哪些地方没有使用"close"或"dispose",从而引发瓶颈。 *分析在你意料之外的分配。 |
Profiling Applications
在这节中,你将创建一个小的C#控制台应用程序例子,并通过使用CLR Profiler了解这个应用程序。
Creating Sample Applications for Profiling
"Sample: ProfilerSample1" 和 "Sample: ProfileSample2."代码如下
ProfilerSample1.cs
ProfilerSample2.cs
To create sample console applications for profiling
1.创建一个ProfilerSample文件夹去存放示例的代码。
2.在ProfilerSample文件夹中,创建2个C#文件,名为ProfilerSample1.cs和ProfileSample2.cs。从“Sample:ProfilerSample1”和“Sample:ProfileSample2”中将代码示例拷贝到文件中。
3.打开cmd命令窗口,找到ProfilerSample文件夹,并通过下面的命令编译代码。(注意设置环境变量)
csc /t:exe /out:ProfilerSample2.exe ProfilerSample2.cs
使用CLR Profiler去分析应用程序
在这节中,你将分析ProfilerSample1.exe。
To use CLR Profiler to profile the application
1.打开CLR Profiler(CLRProfiler.exe).
2.确保下列选项已经勾选:
*Profiling active
*Allocations
*Calls
2.点击Start Application。
3.在打开的窗口中,找到(navigate to)你保存示例代码ProfilerSample文件夹所在位置,并选择profilersample1.exe应用程序。
4.Interact with the application as needed and then close the application.
分析ASP.NET 应用程序
通过下面的步骤去分析asp.net应用程序
1.启动CLR Profiler。
2.确保下列选项已经勾选:
*Profiling active
*Allocations
*Calls
3.在File菜单中点击Profile ASP.NET。
CLR Profiler 完全关闭互联网信息服务(internet infomation services ,iis),添加那些需要分析的环境变量(environment vaiables),重启iis。CLR Profiler然后提示(prompt)你加载ASP.NET应用程序和等待ASP.NET工作京城启动。
4.使用MS的IE浏览你所想分析的ASP.NET应用程序。你总能运行你的Web应用程序通过客户端工具,如Microsoft Application Center Test(ACT,http://msdn.microsoft.com/en-us/library/aa287452.aspx.)。
5.当你已完成应用程序的运行,请点击CLR Profiler窗口中的 Kill ASP.NET。CLR Profiler关闭IIS,移除环境变量,重启IIS。
注意:有时候工具的当前版本不能对第4步页面的加载做出反映。如果出现这个问题,试着改变ASP.NET进程级别(identity)至System在machine.config中的<ProcessModel>中。你完成分析你的应用程序后,确保你改变的应用程序级别再该回到Machine。
识别通常的GC问题(issues)
你能使用CLR Profiler.exe去识别并使与GC有关的问题隔离。
这些包括以下的内存消耗(consumption)问题:
*过度(Excessive)分配
*未知分配
*内存泄漏(leak)
他们总包括以下GC问题:
*过度收集
*长期存在(Long-lived)的对象
*执行GC所花的时间百分比
注意:更多关于使用CLR Profiler解决通常GC问题的详细信息,请看CLRProfiler.doc中的"Common Garbage Collection Problems and How They are Reflected In These Views" ,它在安装CLR Profiler文件夹的位置。
识别你的应用程序在哪分配了内存
你想去处理内存消耗问题,那么知道应用程序在哪做了内存分配是非常重要的。
识别你的应用程序哪分配了内存,有下面几个步骤:
1.在CLR Profiler中启动示例程序。
2.分析内存的分配类型。
3.判定谁分配了内存。
4.评估(evaluate)你能减少那些分配。
第一步:在CLR Profiler中启动示例程序。
打开CLR Profiler并运行你先前(earlier)所创建的ProfilerSample1.exe应用程序。
第二步:分析内存的分配类型
在View菜单上,点击Histogram Allocated Types。CLR Profiler 显示一个类型于图1的窗口。
图1:
这个图表显示了在应用程序运行期间已被分配的对象。在这个例子中,大约2GB的对象被分配,几乎都是字符串。原因是当你在示例代码的方法中操作字符串时,.net分配一个新的字符串空间,拷贝老的并相加组成新的存放进去。(这句话的意思就是当你申明string str="";后你执行str+="new";时先前的str=""所在的空间还是在那,str+="new",是一个新的内存空间,它存放的是""+"new"的结果。)
使用Higtogram Allocated Tyoes视图查看那些大对象(超过85k的)堆分配。你能选择左边特定的柱形条或右边方格,并通过右击他们查看是谁分配了这些内存。显示了一个新的视图,它展现给你一个在你应用程序运行周期内这些对象被谁分配的高级视图。
第三步:Determine Who is Allocating the Memory
在View菜单中,点击Allocation Graph。你也可以通过点击如图1所示的那个视图中的某一个柱形条,右击show who allocated。点击这个菜单项显示关于所选分配的特定详细内容,而不是所有分配。(这句话说的应该是图2视图中的一个个小项)CLR Profiler 显示的图标如图2所示。
视图2:
在这个例子中,你能看见几乎所有的(nearly all of)内存从string.Concat方法处所分配的情况。
Allocation Graph视图能使你:
*看见每个方法的内存分配成本。
*分析那些出乎你意料的分配。
*比较做了相同工作的不同方法。
第四步:Evaluate What You Can Do to Reduce the Allocations
现在你知道你的应用程序在哪分配了内存,评估你能否减少(reduce)这些内存的消耗(consumption)。在这个例子中,一个选择(option)是使用StringBuilder而不是使用string的拼接(concatenation)。
分析你的应用程序的(内存)分配情况
你的应用程序的(内存)分配情况告诉你,对象分配在什么位置,对象的生命周期,GC的行为。轻而易举(walk through)的得知,应用程序持有的对象(和内存)是否比起通常情况下更长。再来看看ProfilerSample2.exe示例。
分析你的应用程序分配情况,通过以下步骤:
1.在CLR Profiler中运行示例程序。
2.识别长期存在的对象。(Identify long-lived objects.)
3.分析GC在你的应用程序中的行为。
4.评估是否可以减少对象的生命周期和如何减少。
第一步:Run CLR Profiler on the Sample Application
启动CLR Profiler和运行ProfilerSample2.exe程序。
第二步:Identify Long-Lived Objects
示例代码分配了100000个SolidBrush对象和一些string,导致总的分配约9MB。这个分配绝大多数是SolidBrush对象。通过选择Histogram Resallocated Types 视图,你能看见大约4MB内存因SolidBrush对象被再分配(reallocate).这个信息指出(indicate),SolidBrush对象在GC后未被清楚,并被提升到了更好的(GC)代。
判定什么类型的对象被提升和这些对象共计使用了多少内存,可以点击View菜单的Objects by Address。如图3所示:
图3:
注意1,2代几乎由SolidBrush对象组成。
第三步:Analyze GC Behavior over the Lifetime of Your Application
点击VIew菜单上的Time Line产看更多详细信息。设置纵坐标(Vertical Scales)为5,横坐标(Horizontal Scales)为1,当滑轮向右移动,你应该看见一个类似图4的窗口。
图4:
在图中,你能看见一个“双锯齿”的样式。GC0代去掉(get rid of)的字符串,但保留(retain)brushes(换句话说,brushes在收集中存活了下来)。不久,GC1代清楚了brushes。
双锯齿样式指示GC0代未能回收(reclaim)所有的内存,对象被更高的代所收集。
在这点上,你能看见那些在GC中存活下来的对象,并且你需要研究他们。首先一种肯能研究领域是SolidBrush终结(finalizer).
在工具的主菜单上,单击Call Tree 打开一个调用的树。查看finalizers列的调用情况,通过查找线程表直到找到finalizer线程。(我的CallTree窗口是自己通过鼠标拉大的,不看是很小的个窗口)
这个树显示NATIVE FUNCTION(UNKNOW ARGUMENTS)已触发了总共1000234次调用。
因为对象么有被清楚直到finalizer线程启动,对象无法作为一个被提升的结果收集。图5显示的就是一个类似树图的窗口。
图5:
第四步:Evaluate Whether and How to Reduce Object Lifetimes
一旦你知道了那些对象是长期存在的,看看你是否能减少他们的生命周期。在这个例子中,你简单的去确保SolidBrush被立刻Dispose在他们不再(on longer)需要的时候,通过把它包含在using 块中。
附加的一些资源:
关于使用CLR Profiler解决通常有关CG问题的详细信息,请看"Common Garbage Collection *Problems and How They are Reflected In These Views," 在CLRProfiler.doc,位于CLRProfiler.exe工具的安装目录中。
*学习关于托管代码的更重要的性能因素(performance factor),请查看MSDN文章,"Writing High-Performance Managed Applications: A Primer," at http://msdn.microsoft.com/library/en-us/dndotnet/html/highperfmanagedapps.asp.
*关于GC的工作信息,和如何优化(optimize)GC,请查看MSDN article, "Garbage Collector Basics and Performance Hints," at http://msdn.microsoft.com/library/en-us/dndotnet/html/dotnetgcbasics.asp.
*关于CLR Profiler执行2个不同方法去解决同一个问题的比较和对照信息,请查看MSDN TV片段,"Profiling Managed Code with the CLR Profiler," at http://msdn.microsoft.com/msdntv/episode.aspx?xml=episodes/en/20030729CLRGN/manifest.xml.