代码改变世界

.net垃圾回收学习【NET Best Practice No: 1:- Detecting High Memory consuming functions in .NET code】【翻译&&学习】

2011-08-30 06:51  一一九九  阅读(250)  评论(0编辑  收藏  举报

From: http://www.c-sharpcorner.com/UploadFile/shivprasadk/452069230108152009163244PM/4520692301.aspx?ArticleID=50bdd822-23d0-4baa-ab0a-21314b94d9e5

.net代码性能降低的一个主要原因是内存消耗。很多开发人员在解决性能瓶颈的时候将精力集中在执行时间上,仅仅有执行时间是不能说明性能问题的。这篇文章讲述使用CLR Profiler研究系统的内存分配。

CLR Profiler 从官方下载即可。作者的版本是2.0版本,有点老了。

Features of CLR profiler

CLR Profiler的主要作用有以下两点:

  • 呈现一个.net application分配了多少内存的完整报告。可以看到每种类型分配多少,每个函数分配了多少,每个方法份分配了多少。
  • 提供了方法调用花了多少时间的报告。

2

Do not use CLR on production and as a starting tool for performance evalution

CLR 是一个侵入式的工具。当你使用CLR Profiler进行程序性能调优的时候,它注入了每个方法中,以生成HeapData。如下图所示:

3

How  Can  we Run CLR Profiler

下载完毕CLR Profiler后,根据处理器类型选择不同的CLRProfiler.exe.  双击启动:

接下来需要决定Profiler程序的什么内容。CLR可以Profiler如下内容: 内存分配和方法调用的次数,所以可以选择需要Profiler的内容然后点击StratApplication即可。如下图:

4

一旦你的程序执行完毕后,可以看到如下图所示的Profiler概况。

5

使用CLR可能遇到的问题

假如你碰到了如下的情况并且CLR没有体制运行,可能是以下两个原因:

  • 你的运行环境是.net20但是你运行的CLR  Profiler的版本是1.1
  • 你没有在GAC中注册ProfilterOBJ.dll

6

将要进行Profiler的应用程序

这个应用程序主要是Profiler  String的+操作和StringBuilder的操作。代码如下所示:

private void UsingSimpleStrings()
{
string strSimpleStrings = "";
for (int i = 0; i < 1000; i++)
    {
        strSimpleStrings = strSimpleStrings + "Test";
    }
}
The function which uses 'StringBuilder' class to do concatenation.
private void UsingStringBuilders()
{
    StringBuilder strBuilder = new StringBuilder();
for (int i = 0; i < 1000; i++)
    {
        strBuilder.Append("Test");
    }
}
Both these functions are called through a button click.
private void btnDoProfiling_Click(object sender, EventArgs e)
{
   UsingSimpleStrings();
   UsingStringBuilders();
}

7

Using CLR  Profiler to profilter our sample

运行CLR Profiler, 点击Start application,  运行程序,关闭程序。可以看到一个概览的窗体。

假如点击histogram按钮的话能够看到每种类型分配的内存的历史图。如下图所示:

8

假如你对每个函数分配了多少内存感兴趣,可以点击以下'Allocation Graph'.。这个图呈现了每个函数消耗了多少内存。由于有非常多的函数,这个报告也比较复杂,以至于我们都不能够找到我们的函数 UsingStringBuilders和UsingSimpleStrings。

9

可以通过查找函数来简化上图,点击右键选择’Find Routine ‘‘,可以看到有两个函数被调用。

10

The search now zooms on the method as shown in the below figure. Now double click on the 'btnDoProfiling_Click' box as highlighted in the below figure.

11

双击后可以看到如下图所示的细节,现在看起来好多了。但是第二个函数去哪里了呢,原来Report是有粒度过滤的。选择Everything就能够看到一切。

12

现在可以看到其他的函数了。可以看到’UseSimpleStrings‘和’UseStringBuilders’所占的内存的大小。如下图:

13

That was a tough way an easy way

假如我们有一千个函数的话,是不可能每个调用图都能够看到的想要的函数的,比较好的方式导出细节到一个Excel中,然后再分析。

14

Once you click on call tree you will be shown something as shown below. Click on view --> All functions --> you will be shown all functions --> click on file and save it as CSV.

15

Once you have exported the complete data to CSV, you can easily locate your methods and functions and see how much data has been allocated.

16

Simplifying results using Comments

假如你知道要优化哪个方法,你可以在方法调用的时候激活优化。也就是说我们可以在应用程序中激活CLR Profiler。

为了在代码中使用Profiler, 需要添加引用“CLRProfilerControl.dll”. 这个DLL和Profiler.exe在同一目录下。

然后你可以直接在代码中调用profiler control,如下所示:

private void btnDoProfiling_Click(object sender, EventArgs e)
{
   CLRProfilerControl.LogWriteLine("Entering loop");
   CLRProfilerControl.AllocationLoggingActive = true;
   CLRProfilerControl.CallLoggingActive = true;
   UsingSimpleStrings();
   UsingStringBuilders();
   CLRProfilerControl.AllocationLoggingActive = false;
   CLRProfilerControl.CallLoggingActive = false;
   CLRProfilerControl.LogWriteLine("Exiting loop");
   CLRProfilerControl.DumpHeap();
}

然后运行CLR Profiler,启动我们的应用程序。需要保证没有选择profile active因为我们要在代码中激活这些内容。
17

现在你可以在Histogram中看到有限的数据。只有很少的来自“String.String”和“System.Text.StringBuilder”类型的的内存分配。

18

而且内存分配图现在也很整洁了。之前的一团糟的图形已经没有了。注意这里我们仍然需要在Detail中选择”EveryThing“粒度。

19

As Said before do not get carried away with execution time

在概览页可以看到Comments按钮。点击它将会看到启动和结束时间。不要忘了在代码中移除这一部分。

20

Entering loop (1.987 secs)
Exiting loop (2.022 secs)

结论:

  • CLR Profiler可以用来查找函数、类、程序集分配的内存。
  • CLR Profiler不应该用在生产环境中。
  • CLR Profiler不应该作为评估性能的一个起点。我们可以通过运行一个计数器,得到执行时间较长的方法,然后通过CLR来优化。
  • 可以使用Histogram查看内存分配和Call Graph来看方法级别的内存分配。
  • 如果你知道那些代码需要优化,可以在Application中激活它。