哈哈,昨天没事做,在CodeProject瞎逛,偶然看到这篇文章,居然读得懂,于是就翻译了一下,当练习英语,同时增强对文章的理解,发现再次翻译对于文章的一些细节问题又有更好的理解。下面是翻译内容,虽然翻译出来后很像小学生写作文,读起来很拗口,希望大家多多提出宝贵意见,谢谢。

原文地址:

http://www.codeproject.com/KB/aspnet/BestPrctice1.aspx#As%20said%20before%20do%20not%20get%20carried%20away%20with%20execution%20time

支持翻译练下英语,目前该系列确实更新到五了。
地址为:
.NET Best Practice No: 3:- Using performance counters to gather performance data
http://www.codeproject.com/KB/aspnet/DOTNETBestPractices3.aspx
Best Practice No 4:- Improve bandwidth performance of ASP.NET sites using IIS compression
http://www.codeproject.com:80/KB/dotnet/DotNetBestPractices4.aspx
Best Practices No 5: - Detecting .NET application memory leaks
http://www.codeproject.com/KB/dotnet/BestPractices5.aspx

 

检查.net代码中占用高内存函数

介绍

非常感谢 Mr. Peter Sollich

使用 CLR profiler

CLR profiler 功能

不要在产品中使用CLR profiler或者一开始就作为性能检测工具

如何使用CLR profiler?

使用CLR profiler可能遇到的问题?

一个简单的示例

使用CLR profiler来检测我们的示例

其它更简便的方法

使用comments简化结果

不要太过于关心执行时间

总结

简介

.net中内存消耗是一个减低性能的重要因素。许多开发者都只关注执行时间使.net应用程序出现性能瓶颈。
但是仅通过执行时间来并不能很清晰的判断性能问题所在。好吧,那么最重要的问题就是去理解,哪个函数,
程序集或者类消耗了多少内存。在本篇介绍中,我们将会知道如何找出那个函数占用了多少内存。本问主要讨论
使用CLR profiler来了解内存分配的最佳实践。

非常感谢 Mr. Peter Sollich

在开始本篇文章前,我们首先感谢CLR 性能架构师Peter Sollish,写了如此详细的帮助文档。安装CLR profiler后
请别忘了阅读Peter Sollich写的详细帮助文档。

非常感谢,如果你看到我这篇文章,请让我知道。

使用 CLR profiler

CLR profiler 工具是由微软提供的,用于检测你的.net代码中是如何分配内存的工具。你可以通过下面链接下载:
http://www.microsoft.com/downloads/details.aspx?familyid=A362781C-3870-43BE-8926-862B40AA0CD0&displaylang=en

注:CLR profiler有两个版本,一个是.net 1.1,另一个是.net 2.0. 对于2.0 CLR profiler,你可以通过
http://www.microsoft.com/downloads/details.aspx?familyid=A362781C-3870-43BE-8926-862B40AA0CD0&displaylang=en 下载
或者通过http://www.microsoft.com/downloads/details.aspx?familyid=86ce6052-d7f4-4aeb-9b7a-94635beebdda&displaylang=en#Overview 下载1.1版本

下载CLR profiler,解压缩后,就可以在Binaries文件夹下运行程序。

如果你下载了2.0的CLR profiler,它提供了x86和x64两种环境,所以请确定运行正确的版本。

CLR profiler 功能

CLR profiler是用于理解.net应用程序中内存如何分配的最好工具。它的两个主要功能:
提供.net 应用程序内存分配的完整报告。所以你可以查看每一个类型,函数,程序集的内存分配报告
提供了调用方法所消耗的时间

不要在产品中使用CLR profiler或者一开始就作为性能检测工具

CLR是一个注入式工具。换句话说,它使用自己的逻辑来将转储应用程序中每个函数/类/模块的内存。
也就是它会干扰原有程序逻辑。例如,一个应用程序调用function 1和function 2,当检测你的程序时,
CLR profiler会在每个函数执行后注入内存堆数据,如下图:

换言之,你不能使用CLR profiler来查看程序的运行时间,因为事实上它会使你的用于程序慢到10到100倍。
你会得到一个错误的结果。

因为它是这样的一个注入式工具,所以不要在生产环境中使用。

首先,不要一开始就使用CLR profiler工具来分析你的性能问题。它只是在当你发现某个函数或者类有内存问题时才使用。
最合适的方法是使用性能计数器查找那个方法或者函数占用了较长时间,然后再使用CLR profiler来查看内存占用情况。

如何使用CLR profiler?

从微软下载CLR profiler,解压文件。打开解压文件夹中的Binaries目录,找到合适的版本,运行‘CLRProfiler.exe’。你会看到
如下图界面。

首先选择我们需要检测的程序。有两样东西可以检测的:一个就是内存的分配另一个则是一个方法被调用的次数。
勾选你需要检测的内容,点击“start application”。

检测完成后,你可以看到像下面图片中的一个概要。它是一个非常复杂的报告,之后我们会通过一个简单的例子来看简单流程。

使用CLR profiler可能遇到的问题?

当运行CLR profiler时,我们可能遇到一些问题。如果你看到以下界面同时程序不会停止时,可能是以下两个原因造成的:
你使用了.net 2.0但是运行的是CLR profiler 1.1
你没有在GAC注册RrofilerOBJ.dll

一个简单的检测例子

我们要检测的例子非常简单,使用一个简单的按钮,调用两个函数"UseSimpleStrings"和"UseStringBuilders".
两个函数都是用来连接字符串。一个使用"+"号连接,另一个则使用StringBuilder类。我们循环连接1000次。

private void UsingSimpleStrings()
{
string strSimpleStrings="";
for (int i = 0; i < 1000; i++)
{
strSimpleStrings = strSimpleStrings + "Test";
}

}

使用StringBuilder类连接

private void UsingStringBuilders()
{
StringBuilder strBuilder = new StringBuilder();
for (int i = 0; i < 1000; i++)
{
strBuilder.Append("Test");
}
}

两个函数都通过按钮时间调用:

private void btnDoProfiling_Click(object sender, EventArgs e)
{
UsingSimpleStrings();
UsingStringBuilders();
}

使用CLR profiler来检测我们的示例

接下来我们将使用profiler来检测我们例子中的函数占用了多少内存。点击“Start Application”,
选择应用程序,然后点击应用程序中的按钮,然后关闭应用程序,你会看到弹出一个概要窗口。

点击柱状图,你可以看到每种类型的内存分配情况。我知道这非常混乱。所以我们不管它。o(∩_∩)o

如果你对没有函数是分配了多少内存,你可以点击"Allocation Graph"。它会告诉你每个函数分配了多少内存。
不过这个报告非常复杂,因为里面有好多函数,我们很难去定位到我们的两个函数"UsingStringBuilders"和"UsingSimpleStrings"

为了简化上面的图片,我们使用右键中的一些过滤。我们使用"Find Route"过滤一些不必要的数据。输入按钮的事件名
从这个事件,我们就可以找到调用的两个函数。

搜索后图片移动到如下图所示。双击下图中高亮的"btnDOProfiling_Click"框。

双击后,你可以看到如下图的详细信息。现在好点了,但是第二个函数不见了,只显示了"UseSimpleStrings"函数。
这是因为这个报告是大概的,所以选择“Detail”区域中0(everything)即可以看到所有函数。

现在你可以看到其它函数了。那26bytes是啥呢?它只是函数执行时,对字符串的额外操作。所以我们可以忽略它
让我们来关注一下"UseSimpleStrings"和"UseStringBuilders"。你可以看到简单字符串使用3.8M。而StringBuilder只使用了26kb
因此,StringBuilder比简单的字符串连接要省更多的内存。

That was a tough way any easy way(这句不知咋翻译)

上面使用的方法比较麻烦。假如你有1000个函数,你要检测这些函数占用的内存。这是非常不可能去看每个调用图,找出你的函数。

最好的方式就是导出一个详细的报告到excel文件,然后分析这些数据。因此,点击"view"中的"call tree"

点击call tree后弹出如下对话框。点击view 中的"all function"。你尅看到所有的function,点击File中的Save保存为CSV文件。

导出成功后,你就可以很方便的定位到你的方法或者函数,查看分配了多少内存。

使用comments简化结果

如果你知道你要检测哪个方法,你可以在方法调用的时候启动profiler。也就是说你可以在应用程序中启动CLR profiler.
为了在C#代码中启用profiler,你首先必须添加"CLRProfilerControl.dll"的引用。你可以在profiler程序所在文件夹下找到该dll
这样你就可以直接在你的代码中调用profiler了,如下代码段。我们在调用两个字符串连接函数之前先启用profiler。
函数调用完成后,再禁用profiler

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启动程序,因为我们在已经在代码中启用profiling,所以我们就勾除Profiling active选项。

这时候你可以看到柱状图数据比较少,你会看到他只记录了"System.String"和"System.Text.StringBuilder"两种类型的内存分配。

但你看到分配图时你会发现变得非常简洁。之前凌乱的视图不见了,取而代之的是简单集中的图片。记得点击"Everything"查看所有函数。

不要太过于关心执行时间

在Summary界面,你可以看到一个"comments"按钮。点击该按钮,你可以看到程序的开始和结束时间。请不要在意这个时间记录,就像
我们之前提到的,一个侵入式工具返回执行时间结果是不正确的。

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

总结

CLR profiler可用于查看函数,类和程序集的内存分配,以评价程序的性能。
它不应该在生产环境中使用。
它不应该是性能检测的首选工具,我们应该首先选择性能计数器,获取那个方法执行时间较长,然后在用CLR profiler找出真正原因。
你可以使用柱状图来查看内存分配,函数调用图来查看函数所占用内存。
如果你知道哪个函数要检测,那么你可以在程序中启动profiler

总而言之,作为一个查看内存分配的工具,没有任何其它工具能够比得上CLR profiler了。

http://www.codeproject.com/KB/aspnet/BestPrctice1.aspx#As%20said%20before%20do%20not%20get%20carried%20away%20with%20execution%20time

分类: C#

检查.net代码中占用高内存函数(翻译)的更多相关文章

  1. Python 函数式编程 & Python中的高阶函数map reduce filter 和sorted

    1. 函数式编程 1)概念 函数式编程是一种编程模型,他将计算机运算看做是数学中函数的计算,并且避免了状态以及变量的概念.wiki 我们知道,对象是面向对象的第一型,那么函数式编程也是一样,函数是函数 ...

  2. JS中的高阶函数

    JS中的高阶函数 高阶函数是指以函数作为参数的函数,并且可以将函数作为结果返回的函数. 1. 高阶函数 接受一个或多个函数作为输入 输出一个函数 至少满足以上一个条件的函数 在js的内置对象中同样存在 ...

  3. Java中的函数式编程(五)Java集合框架中的高阶函数

    写在前面 随着Java 8引入了函数式接口和lambda表达式,Java 8中的集合框架(Java Collections Framework, JCF)也增加相应的接口以适应函数式编程.   本文的 ...

  4. Python中的高阶函数与匿名函数

    Python中的高阶函数与匿名函数 高阶函数 高阶函数就是把函数当做参数传递的一种函数.其与C#中的委托有点相似,个人认为. def add(x,y,f): return f( x)+ f( y) p ...

  5. ES6中的高阶函数:如同 a => b => c 一样简单

    作者:Sequoia McDowell 2016年01月16日 ES6来啦!随着越来越多的代码库和思潮引领者开始在他们的代码中使用ES6,以往被认为是"仅需了解"的ES6特性变成了 ...

  6. python中的高阶函数

    高阶函数英文叫Higher-order function.什么是高阶函数?我们以实际代码为例子,一步一步深入概念. 变量可以指向函数 以Python内置的求绝对值的函数abs()为例,调用该函数用以下 ...

  7. scala中的高阶函数

    版权申明:转载请注明出处. 文章来源:http://bigdataer.net/?p=332 排版乱?请移步原文获得更好阅读体验 1.scala中的函数 scala是一门面向对象和函数式编程相结合的语 ...

  8. Javascript中的高阶函数介绍

    高阶函数:高阶看上去就像是一种先进的编程技术的一个深奥术语,一开始我看到的时候我也这样认为的. Javascript的高阶函数 然而,高阶函数只是将函数作为参数或返回值的函数.以下面的Hello,Wo ...

  9. Swift 中的高阶函数和函数嵌套

    高阶函数 在Swift中,函数可做为“一等公民”的存在,也就意味着,我们可以和使用 int 以及 String 一样,将函数当做 参数.值.类型来使用. 其中,将函数当作一个参数和值来使用可见下: t ...

随机推荐

  1. ADB Offline

    终极可能原因:版本太旧 http://stackoverflow.com/questions/14993855/android-adb-device-offline-cant-issue-comman ...

  2. poj 2409(polya定理模板)

    题意:给你n种颜色和m个小球,问你有多少种不同的方案! 分析:作为模板.. 代码实现: #include <iostream> #include <cstdio> #inclu ...

  3. java多态中哪些成员具备多态特性

    在多态的学习中,当子类继承父类时,子类中的变量哪些具备多态特性,哪些不具备多特特性. 代码: class Father{ public static int x=10; public int y=11 ...

  4. top命令 Linux查看CPU和内存使用情况

    一.top命令 top命令是一个功能十分强大的监控系统的工具,对于系统管理员而言尤其重要.但是,它的缺点是会消耗很多系统资源. 在系统维护的过程中,随时可能有需要查看 CPU 使用率,并根据相应信息分 ...

  5. C++中,申请字符串数组可用new实现

    C++中,申请字符串数组可用new实现: char ** list = new char*[MAX_NUM]; for (int i = 0; i< MAX_LOOP; i++) list[i] ...

  6. C# 一个简单的秒表引发的窗体卡死问题

    一个秒表程序也是我的一个心病,因为一直想写这样的一个东西,但是总往GUI那边想,所以就比较怵,可能是上学的时候学MFC搞出的后遗症吧,不过当我今天想好用Win Form(话说还是第一次写win for ...

  7. Cocos2d-android (03) 向量

    向量的基本运算及动作 import org.cocos2d.actions.interval.CCJumpBy; import org.cocos2d.actions.interval.CCMoveB ...

  8. 黑马程序员——Block数据类型

    Block数据类型,又被称为代码段.因为它可以封装一段代码.苹果官方建议多用block.因为在多线程控制.异步任务,集合遍历.集合排序.动画转场等方面用的很多. Block的特点: 1.Block 用 ...

  9. .hpp文件

    hpp在C++中的含义 以前在开源代码里面遇到过,今天看boost源码的时候又遇到了,故学习一下. hPP,计算机术语,用C/C++语言编写的头文件,通常用来定义数据类型,声明变量.函数.结构和类.而 ...

  10. linq数据使用

    取出数据库满足条件的记录的ID,把值放到list中 ) { int userid = Convert.ToInt32(Request.Cookies["id"].Value); v ...