`
djdnmq
  • 浏览: 8247 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

.net 最佳实践一:监测.net代码中的高内存消耗函

阅读更多

.net 最佳实践一:监测.net代码中的高内存消耗函数

简介和目标

导致.NET 代码性能下降的重要因素之一是内存消耗。 许多开发人员只是主要用执行时间来确定.NET 应用程序的性能瓶颈。 只测量执行时间并不清楚知道性能问题之所在。 好,要说的和要做的一个最大任务就是知道哪些函数、 程序集或类占用了多少内存。 在本教程中,我们将看到我们如何找出哪些函数消耗多少内存。 本文讨论的最佳实践涉及使用 CLR 探查器(CLR profiler)研究内存分配。

请随时到 http://www.questpond.com下载我的涵盖.NET ASP.NET SQLServer WCF WPFWWF的免费500个问题和回答的电子书。

 

非常感谢Peter Sollich先生

在开始本文时,首先要感谢CLR性能架构师Peter Sollich先生,他给CLR 探查器写了详细的帮助。当你安装CLR 探查器时不要忘记阅读Peter Sollich先生写的详细的帮助文档。

 

CLR Profiler to rescue

CLR探查器是一个帮助我们对.net代码监测内存分配情况的工具。CLR探查器由微软提供,你可以从下面的网址下载:

http://www.microsoft.com/downloads/details.aspx?familyid=A362781C-3870-43BE-8926-862B40AA0CD0&displaylang=en

注意:CLR探查器有针对.net 1.12.0框架的两个版本。2.0框架的版本在http://www.microsoft.com/downloads/details.aspx?familyid=A362781C-3870-43BE-8926-862B40AA0CD0&displaylang=en1.1的版本在http://www.microsoft.com/downloads/details.aspx?familyid=86ce6052-d7f4-4aeb-9b7a-94635beebdda&displaylang=en#Overview

下载并解压CLR探查器之后,可以从bin目录下运行CLRProfiler.exe

如果你下载的是2.0版本的CLR探查器,它提供针对X86X64的两种执行环境,清确认你运行了正确的版本。

 

CLR探查器特性

如果你企图了解.net应用程序代码是如何 进行内存分配的,CLR探查器是最好的工具。它有两个重要的功能:

  • 给出一个.net应用程序是如何进行内存分配的报告。这样你就可以看到一个关于每一种数据类型,函数,和方法等是如何进行内存分配的完整报告。
  • 它同时也提供调用方法耗费的时间。

 

不应在产品中使用CLR探查器作为性能评估工具

CLR探查器是一嵌入工具,换句话说,它为应用程序内的每一个函数、类、模块在内存使用方面执行它自己的逻辑。比如说你有一个应用程序调用了函数1和函数2,当你使用CLR探查器探测应用程序时,它在每一个函数调用之后插入关于内存堆数据的使用情况,如下

换句话说,不要使用CLR探查器来查看你的应用程序的执行时间,它会减慢你的应用程序10100倍,你会因错误的结果你死去。

如上所说,它是一个侵入式工具,你永远不要在你的产品环境中使用它。

第一,你永远不要一开始就用CLR探查器来分析你的性能问题。它更多的是用在第二步,在这里你可以调整一个有内存问题的函数或类。更可能的情况是首先使用性能计数器找到哪一个方法或函数的执行用了比较长的时间,然后再使用CLR探查器查看内存分配情况是怎么样的。

怎么运行CLR探查器

当你从微软网站下载CLR探查器后,把文件解压到一个目录中。转到解压后的目录下的Binaries目录,选择并运行‘CLRProfiler.exe’ CLR探查器运行如下图所示。

第一步要确定我们想探查什么,有两个探查选项,一是内存分配,另一是调用方法的次数,然后选择你要探查的数据,点击开始应用程序。

当完成之后,你会看到如下所示的探查结果的完整摘要。那是一个复杂的报告,当我们探查一个简单的应用程序时,我们想看到一个简化的结果。

 

使用CLR探查器面临的问题

运行CLR探查器时我们面临一些问题。如果我们看到了下面的界面,但它并没有结束,可能有两个原因:

  • 你的环境是.net 2.0,但你运行的CLR探查器是1.1的。
  • 你没有在GAC中注册ProfilerOBJ.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探查器探查我们的简单程序

现在我们了解我们的应用程序,我们尝试使用CLR探查器探查哪一个函数使用了多少内存。然后点击开始应用程序,找到我们的应用程序的exe文件,选上内存分配复选按钮,并关闭应用程序。现在会弹出一个完整的摘要对话框。

点击显示柱状图按钮,你会看到每种数据类型内存分配情况。我知道这非常容易搞混,所以保留了这个截图。

  

如果你对每一个函数分配了多少内存感兴趣,点击‘Allocation Graph’,它给出每一个函数消耗了多少内存。因为有很多函数,很多方法,所以这个报告常常被搞混,并且我们不能我们的两个函数‘UsingStringBuilders’  ‘UsingSimpleStrings’字符串。

为了简化上面的图形,右击会弹出一些过滤选项,我们使用“查找过程”(‘Find Routine’)搜索过滤掉不需要的数据,我们键入按钮的点击事件名称,从点击事件调用了两个函数。

探索结果放大到如下图所示的方法上,在如下高亮显示的‘btnDoProfiling_Click’框上双击:

双击后我们会看到下面的细节,它现在更好一些。但是第二个函数消失到哪了呢。它只显示出了‘UseSimpleStrings’函数。这是因为这个报告是粗略的,在“所有”(0(everything))上点击你就会看到所有的函数。

现在可以看到另一个函数了。26个字节是什么?那是当函数被调用时额外的字符串操作所必须的,所以我们可以不再会它。我们把注意力集中到现在都可以看到的两个函数‘UseSimpleStrings’  ‘UseStringBuilders’上。你能看到字符串连接消耗了3.8MB,而使用StringBuilder对象只消耗了16KB。所以使用StringBuilder对象比使用简单字符串连接消耗更少的内存。

 

That was a tough way any easy way(不知道是什么意思)

上面所示的方式感到很吃力,假如你有1000个函数,你想分析哪一个函数消耗了多少内存,事实上是不可能通过查看每一个调用图,来找到你的函数。

最好的方法就是把报告导出到excel中然后再分析,点击‘view’菜单下的‘call tree’。

当你点击‘call tree’之后,就显示如下所示的内容,再点‘view’-‘all function’,就能看到所有的函数,再点文件保存成csv文件。

当导出到csv文件完成后,你就很容易定位到你的方法和函数,并看到分配了多少内存。

使用注释简化结果

如果你知道你要探测哪一个方法,你可以只在当该方法被调用时启用探测器,换句话说,你可以从应用程序启动CLR探测器。

为了从C#代码中启动探测器,首选需要引用‘CLRProfilerControl.dll’,可以从Profiler.Exe所在目录找到这个DLL

你可以如下代码段所示直接在代码中调用这个探测器控件,我们在调用两个字符处理函数前启用探测器,在调用函数结束后停止探测器。

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探测器并开始我们的应用程序,请确保你没有启用探测的活动复选项,因为我们会在代码中启用探测器。

现在如果你查看柱形图,你将看到有限的数据,你看到它只记录了‘System.String’  ‘System.Text.StringBuilder’ 数据类型内存分配消耗情况。

如果你查看分配图,你就会看到它现在非常简洁。那个杂乱的视图完全的不见了,现在看到的是一个漂亮简单的视图。在‘Everything’上点击就看到保留的函数。

 

如前所说,不要完全相信执行时间

在摘要页你能看到 comments 按钮,如果你点击comments按钮就会显示开始时间和结果时间。不要完全相信这个时间记录,我们前面明确的指出过它是一个侵入式工具,所以结果并不正确。


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

 

结论

  • CLR探测器可以用来查找函数、类和程序集的内存分配情况,并评估性能。
  • 它不能用于产品。
  • 它不能用于性能评估的开始点。我们应该先运行性能计数器,得到方法的高效执行时间,然后再使用CLR探测器查看真实的原因。
  • 可以使用柱形图查看内存分配情况,使用调用图查看方法智能内存分配情况。
  • 如果你知道你要探测哪一个方法,你可以从程序启动探测器。

 

用上面的一切推演出一个作为最佳实践的结论,当你要查看内存分配情况时,没有任何东西能和CLR探测器匹敌。

 

源代码

可以从这里找到示例中的源代码。

 

分享到:
评论

相关推荐

    .net CPU及内存监测

    在.NET开发中,对应用程序的性能监控是至关重要的,尤其是CPU和内存的使用情况。`.NET CPU及内存监测`这个话题涉及到如何利用Windows API来实时获取系统资源的使用信息。在Windows操作系统中,开发者可以调用WIN32 ...

    CLRProfiler 内存泄漏工具 .net

    CLRProfiler是.NET Framework中用于诊断内存管理问题的强大工具,尤其是针对内存泄漏的检测。它能够帮助开发者深入理解应用程序在运行时如何使用内存,以及何时和为何会出现内存消耗异常的情况。以下是对这个工具...

    vc.net实现的内存占用显示

    在本文中,我们将深入探讨如何使用VC#.NET来实现一个内存占用显示的程序。这个程序能够监测和展示系统的物理内存、虚拟内存以及内存使用率等关键指标,这对于系统监控和性能优化至关重要。 首先,我们需要理解内存...

    C#-实时监测CPU及内存

    在本文中,我们将深入探讨如何使用C#进行系统监测,特别是实时监测CPU和内存的使用情况。C#是一种广泛应用于Windows平台的编程语言,尤其适用于开发桌面应用和系统级工具。利用C#,我们可以轻松地获取系统性能数据,...

    asp.net网站性能优化

    在IT领域,尤其是在Web开发中,ASP.NET网站的性能优化是一项关键任务,旨在提升网站的运行速度和响应能力。本文将深入探讨与标题和描述相关的关键知识点,包括但不限于:数据库查询优化、数据处理策略、页面加载优化...

    ASP.NET应用程序性能测试

    服务器操作系统自带的“管理工具”中的“性能”计数器是一个强大的监控工具,它能够实时监测服务器的各项性能指标,如CPU使用率、内存占用、磁盘I/O和网络流量等,这对于诊断应用程序性能问题非常有用。通过这些...

    基于VB.NET的系统监控软件设计

    【标题】"基于VB.NET的系统监控软件设计"是一个项目,旨在利用VB.NET这一编程语言构建一款能够实时监测和管理计算机系统的应用。VB.NET是Microsoft .NET Framework的一部分,提供了丰富的库和工具,使得开发人员可以...

    .NET 内部效能插件

    标题中的".NET 内部效能插件"指的是一个专门针对.NET框架的应用程序,用于提升和监控系统的性能。这个插件可能包含了一些自定义工具或组件,使得开发者在Release模式下可以更方便地分析和优化其应用程序的性能,而...

    Windows Embedded从入门到精通系列课程(6):深入探索 .NET Micro Framework 应用开发

    在内存管理和资源优化方面,课程会强调在有限资源下如何有效地分配和使用内存,以及如何优化代码以减少内存消耗。这对于嵌入式系统尤为重要,因为这些系统通常具有严格的资源限制。 此外,课程还会涉及设备驱动的...

    asp.net探针,aspx探针,asp探针

    ASP.NET探针是一种用于监测和诊断ASP.NET应用程序性能和运行状态的工具。它可以帮助开发者和运维人员了解应用程序的实时运行情况,包括请求处理、错误跟踪、资源使用等关键信息。在描述中提到的情况,看来是有人在...

    Eclipse使用SizeOf.jar工具监测内存占用

    有时,为了减少对数据库的频繁访问,提高系统的响应速度,我们会选择将一部分常用的数据缓存在内存中。然而,这种做法也会带来一定的风险——如果内存占用过大,可能会导致系统出现性能问题甚至崩溃。 在这样的背景...

    asp.net 探针

    ASP.NET探针是一种用于监测和诊断ASP.NET应用程序性能和健康状况的工具。它提供实时的、深入的应用程序洞察,帮助开发者识别潜在的问题,优化代码,以及确保web应用的稳定性和效率。本文将深入探讨ASP.NET探针的工作...

    C# 心跳包(服务端,客户端)

    10. **性能优化**:在设计心跳包系统时,还需要考虑性能优化,比如最小化心跳包的大小、减少不必要的CPU或内存消耗、合理利用缓存等。 这个"C# 心跳包(服务端,客户端)"项目,通过ChattingSolution文件可能包含了...

    LvServerInfo .NET源码探针

    1. **性能计数器监测**:LVServerInfo能够收集.NET应用程序的各种性能计数器,如CPU使用率、内存占用、线程数量、I/O操作等,这些指标对于评估系统负载和资源消耗至关重要。 2. **异常跟踪与日志记录**:探针可以...

    wpf实现的cpu与物理内存使用情况

    在本文中,我们将深入探讨如何使用Windows Presentation Foundation (WPF) 来实时监控和展示系统的CPU使用率和物理内存消耗情况。WPF是.NET Framework的一部分,它为开发人员提供了丰富的功能来创建美观且功能强大的...

    Sympact运行JS脚本并分析其执行时间CPU使用情况和内存使用情况

    JavaScript是Web开发中不可或缺的一部分,主要用于前端交互和服务器端编程。...在实际使用中,结合JavaScript开发的最佳实践,如避免全局变量、合理使用闭包、控制回调地狱等,可以显著提升JavaScript代码的性能。

    Smart Client系列课程(5):托管代码的增强调试功能(Video)

    此外,还将讲解如何利用性能分析器来监测资源消耗,从而优化应用的资源利用率。 “增强调试功能”这部分可能会涵盖诸如调试诊断工具(如CLR Profiler)的使用,这些工具可以帮助开发者追踪对象生命周期,识别内存...

    添加和移除内存压力应用程序示例

    在.NET环境中,如VB(Visual Basic)和CS(C#)代码中,垃圾收集机制自动管理内存,但开发者仍然需要确保正确处理对象引用,防止内存泄漏。通过释放不再使用的对象,可以降低内存压力,提高系统性能。 在VB和CS文件...

Global site tag (gtag.js) - Google Analytics