检查.net代码中占用高内存函数(翻译)
哈哈,昨天没事做,在CodeProject瞎逛,偶然看到这篇文章,居然读得懂,于是就翻译了一下,当练习英语,同时增强对文章的理解,发现再次翻译对于文章的一些细节问题又有更好的理解。下面是翻译内容,虽然翻译出来后很像小学生写作文,读起来很拗口,希望大家多多提出宝贵意见,谢谢。
原文地址:
支持翻译练下英语,目前该系列确实更新到五了。
地址为:
.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了。
分类: C#
检查.net代码中占用高内存函数(翻译)的更多相关文章
- Python 函数式编程 & Python中的高阶函数map reduce filter 和sorted
1. 函数式编程 1)概念 函数式编程是一种编程模型,他将计算机运算看做是数学中函数的计算,并且避免了状态以及变量的概念.wiki 我们知道,对象是面向对象的第一型,那么函数式编程也是一样,函数是函数 ...
- JS中的高阶函数
JS中的高阶函数 高阶函数是指以函数作为参数的函数,并且可以将函数作为结果返回的函数. 1. 高阶函数 接受一个或多个函数作为输入 输出一个函数 至少满足以上一个条件的函数 在js的内置对象中同样存在 ...
- Java中的函数式编程(五)Java集合框架中的高阶函数
写在前面 随着Java 8引入了函数式接口和lambda表达式,Java 8中的集合框架(Java Collections Framework, JCF)也增加相应的接口以适应函数式编程. 本文的 ...
- Python中的高阶函数与匿名函数
Python中的高阶函数与匿名函数 高阶函数 高阶函数就是把函数当做参数传递的一种函数.其与C#中的委托有点相似,个人认为. def add(x,y,f): return f( x)+ f( y) p ...
- ES6中的高阶函数:如同 a => b => c 一样简单
作者:Sequoia McDowell 2016年01月16日 ES6来啦!随着越来越多的代码库和思潮引领者开始在他们的代码中使用ES6,以往被认为是"仅需了解"的ES6特性变成了 ...
- python中的高阶函数
高阶函数英文叫Higher-order function.什么是高阶函数?我们以实际代码为例子,一步一步深入概念. 变量可以指向函数 以Python内置的求绝对值的函数abs()为例,调用该函数用以下 ...
- scala中的高阶函数
版权申明:转载请注明出处. 文章来源:http://bigdataer.net/?p=332 排版乱?请移步原文获得更好阅读体验 1.scala中的函数 scala是一门面向对象和函数式编程相结合的语 ...
- Javascript中的高阶函数介绍
高阶函数:高阶看上去就像是一种先进的编程技术的一个深奥术语,一开始我看到的时候我也这样认为的. Javascript的高阶函数 然而,高阶函数只是将函数作为参数或返回值的函数.以下面的Hello,Wo ...
- Swift 中的高阶函数和函数嵌套
高阶函数 在Swift中,函数可做为“一等公民”的存在,也就意味着,我们可以和使用 int 以及 String 一样,将函数当做 参数.值.类型来使用. 其中,将函数当作一个参数和值来使用可见下: t ...
随机推荐
- 【英语】Bingo口语笔记(37) - 动物的多种表达
let the cat out of the bag.不在袋子中的猫 指秘密被泄露 dog tired 累成狗 doggy bag 食品袋
- Eclipse 打开编辑文件所在文件夹方法
一个便捷的方法在eclipse的菜单中,依次点击Run->External Tools-> External Tools configurations添加一个新的工具 OpenContai ...
- 《Unix网络编程》卷2 读书笔记 第3章- System V IPC
1. 概述 三种类型的System V IPC:System V 消息队列.System V 信号量.System V 共享内存区 System V IPC在访问它们的函数和内核为它们维护的信息上共享 ...
- 安装完eclipse,dbwear后,需要在他们解压文件.ini下加上你liux的jdk的安装路径,才能正常使用
-vm/usr/java/jdk/jdk1.6.0_45/bin/java
- 一篇关于apache commons类库的详解
1.1. 开篇 在Java的世界,有很多(成千上万)开源的框架,有成功的,也有不那么成功的,有声名显赫的,也有默默无闻的.在我看来,成功而默默无闻的那些框架值得我们格外的尊敬和关注,Jakarta C ...
- 【剑指offer 面试题38】数字在排序数组中出现的次数
思路: 利用二分查找,分别查找待统计数字的头和尾的下标,最后做差加一即为结果. C++: #include <iostream> #include <vector> using ...
- Windows下Cygwin中使用NCView
1. 使用cygwin的setup.exe安装 NetCDF, HDF5, Curl, libXaw, libICE, udunits, libexpat 和 libpng: 在选择库界面搜索:&qu ...
- 解决g++:command not found(centos7.0)
问题背景,因为装了虚拟机,系统为centos7.0,由于是纯净版,没有gcc,使用命令yum install gcc安装了gcc,但是没安装g++,导致g++:command not found问题. ...
- 第二百零五天 how can I 坚持
身体无论什么时候都是最重要的.肝血管瘤,头一次听说,应该没什么大碍.父母年龄大了,我们也该尽快把自己的事情处理好,让他们放心了. 规律作息,合理饮食,多注意锻炼. 该怎么办.不能这拖下去. 好好规划下 ...
- vim之vba文件
[vim之vba文件] Vimball 官方描述: The vimball plugin facilitates creating, extracting , and listing the cont ...