Visual Studio的.NET内存分配分析器解析
Visual Studio 2012拥有丰富的有价值的功能,以至于我听到开发者反馈的需要的新功能新版本已经有了。另外,我听到开发人员询问具体的功能的某个特性,实际上他真正需要的是另外一个功能点。
上面说的两种情况下适用于Visual Studio的.NET内存分配分析器 。 许多开发人员可能会从中受益却不知道它的存在,而另外一些开发者有却对它有不正确的理解。 这样很不好,因为该功能可以提供很多有价值的特定场景; 许多开发在理解的情况下才能发挥其预期的作用。也就是要做到以下两点:第一,知道它的存在,第二,知道如何使用。
为什么内存分析?
当谈到.NET和内存分析,有两个主要的原因之一,可能需要使用一个诊断工具:
1. 发现内存泄漏。
2. 发现不必要的分配。
内存优化的实例
为了更好地理解内存分析器的作用,以及它如何帮助到我们。让我们通过一个示例来理解。
public static async Task<T> WithCancellation1<T>( this Task<T> task, CancellationToken cancellationToken)
{
var tcs = new TaskCompletionSource< bool >();
using (cancellationToken.Register(() => tcs.TrySetResult( true )))
if (task != await Task.WhenAny(task, tcs.Task))
throw new OperationCanceledException(cancellationToken);
return await task;
}
上面这段代码的作用是可以异步的取消正在运行的任务
T result = await someTask;
T result = await someTask.WithCancellation1(token);
如果取消要求在任务完成之前,相关的CancellationToken,一个OperationCanceledException将被抛出。
要了解参与这一方法的分配,我们将使用一个小程序去测试。
using System;
using System.Threading;
using System.Threading.Tasks;
class Harness
{
static void Main()
{
Console.ReadLine(); // wait until profiler attaches
TestAsync().Wait();
}
static async Task TestAsync()
{
var token = CancellationToken.None;
for ( int i=0; i<100000; i++)
await Task.FromResult(42).WithCancellation1(token);
}
}
static class Extensions
{
public static async Task<T> WithCancellation1<T>(
this Task<T> task, CancellationToken cancellationToken)
{
var tcs = new TaskCompletionSource< bool >();
using (cancellationToken.Register(() => tcs.TrySetResult( true )))
if (task != await Task.WhenAny(task, tcs.Task))
throw new OperationCanceledException(cancellationToken);
return await task;
}
}
运行.NET内存分配分析器
要启动内存分配分析器,在Visual Studio中去分析菜单并选择“启动性能向导...”。 这将打开如下所示的对话框:
选择“.NET内存分配(取样)”,单击下一步两次,最后是完成。 在这一点上,应用程序将被启动,并剖析将开始监视它的分配(线束上面的代码也需要你按下“Enter”键) 。 当应用程序完成后,或当你手动选择停止剖析,剖析会加载符号,并开始分析跟踪。 这是一个很好的时间去让自己的一杯咖啡,或午餐,因为这取决于有多少分配发生后,该工具可以需要一段时间才能做到这一点的分析。
当分析完成后,我们看下报告:
从这里,我们可以进一步研究,通过查看分配汇总(从“当前视图”下拉列表中选择“分配”):
在这里,我们能看到一排的被分配的每种类型,同列显示有多少分配被跟踪的信息,有多少空间与分配,以及如何分配映射回该类型的百分比有关。 我们还可以扩展一个条目看,看到这些分配方法的调用堆栈:
通过选择“功能”的观点,我们可以得到一个不同的支点这一数据,高亮它的功能分配的大多数对象和字节:
剖析分析报告并做相应优化
我们可以分析我们的例子中的结果。 首先,我们可以看到,有相当数量的分配在哪里,这可能是令人惊讶的。毕竟,在我们的例子中我们使用WithCancellation1与已经完成了任务,这意味着应该有很少的工作要做(与已完成的任务,没有什么取消).然而从上面的跟踪我们可以看到,我们的例子中的每一次迭代中产生:
- 三种分配Task`1的(我们跑了线束10万次,可以看到有〜300K分配)
- 两个分配task[]
有关任务的辅助业务,它实际上是相当普遍的处理已经完成的任务,因为很多时候,操作执行是异步的,实际上完全同步(例如,在网络流中的一个读操作可以缓冲到内存足够的额外数据来完成后续的读操作)。 因此,优化已经完成的情况下,可以为表现的确有益。 让我们来试试。 这里有一个第二次尝试WithCancellation,一个优化的几个“已完成”的情况:
public static Task<T> WithCancellation2<T>( this Task<T> task,
CancellationToken cancellationToken)
{
if (task.IsCompleted || !cancellationToken.CanBeCanceled)
return task;
else if (cancellationToken.IsCancellationRequested)
return new Task<T>(() => default (T), cancellationToken);
else
return task.WithCancellation1(cancellationToken);
}
此实现检查:
- 首先,无论是任务已经完成或是否提供的CancellationToken无法取消; 在两者的那些情况下,有不需要额外的工作,因为取消不能适用,因此我们可以只返回原始任务立即而不是花费任何时间或存储器中创建一个新的。
- 那么是否取消已要求; 如果有,我们可以分配一个业已取消的任务将返回,而不是花费八个分配我们先前支付给调用我们原来的实现。
- 最后,如果没有这些快速通道申请,我们通过降至调用原始的实现。
再分析我们的微基准,而使用的,而不是WithCancellation1 WithCancellation2提供了大大改善的前景(你很可能会发现,分析的速度远远超过它之前,已经是一个迹象,表明我们已经显著减少内存分配完成)。 现在,我们刚刚有主要业务划分,我们预计,从Task.FromResult一个从线束我们TestAsync方法叫做:
所以,我们现在已经成功了优化,其中任务已经完成,取消在那里不能要求,或者取消已申请的情况。 怎么样的情况下,我们确实需要调用更复杂的逻辑? 是否有可有什么改进?
让我们改变我们的基准来使用,这不是已经由我们引用WithCancellation2,并且还使用可以有取消请求令牌的时间内完成的任务。 这将确保我们使它的“慢”的路径:
using (cancellationToken.Register(() => tcs.TrySetResult( true )))
剖析再次提供了更深入的了解:
在这种缓慢的道路,现在有14%的迭代拨款总额,包括2从我们TestAsync线束(该TaskCompletionSource <int>的我们明确地创建和任务<int>的它创建)。 在这一点上,我们可以使用所有的分析结果提供的信息,了解那里的其余12分配的来源,并随后解决这些问题的是相关的和可能的。 例如,让我们看两个分配具体为:在<> c__DisplayClass2`1实例,这两个动作实例之一。 这两种分配将可能是合乎逻辑的任何人都熟悉的C#编译器如何处理倒闭 。 为什么我们有一个封闭? 由于该行的:
使用(cancellationToken.Register(()=> tcs.TrySetResult( 真 )))
电话注册,是关在'TCS'变量。 但是,这不是严格必需的:该注册方法具有另一个超载,而不是采取一个动作这需要一个Action <object>和该对象的状态被传递给它。 如果我们不是重写此行使用基于状态的过载,以及一个手动缓存的委托,我们能够避免倒闭和这两个分配:
private static readonly Action< object > s_cancellationRegistration =
s => ((TaskCompletionSource< bool >)s).TrySetResult( true );
…
using (cancellationToken.Register(s_cancellationRegistration, tcs))
重新运行探查证实这两个分配不再发生:
从今天开始分析!
分析,发现和消除热点,然后将再次围绕这个周期是改善代码的性能,常见的方法是否使用CPU分析器和内存分析器。 所以,如果你发现内存分配有可能程序的瓶颈,不妨尝试.NET的内存分配分析器。
Visual Studio的.NET内存分配分析器解析的更多相关文章
- [图解tensorflow源码] [转载] tensorflow设备内存分配算法解析 (BFC算法)
转载自 http://weibo.com/p/1001603980563068394770 @ICT_吴林阳 tensorflow设备内存管理模块实现了一个best-fit with coales ...
- visual studio如何检查内存泄露?
Visual Studio有专门的插件叫做Visual Leak Detector (VLD)Visual Leak Detector for Visual C++ 2008/2010/2012/20 ...
- java 内存分配全面解析
JVM是什么? 首先要知道的是Java程序运行在JVM(Java Virtual Machine,Java虚拟机)上;可以把JVM理解成Java程序和操作系统之间的桥梁,JVM实现了 Java的平台无 ...
- Java静态内存与动态内存分配的解析
1. 静态内存 静态内存是指在程序开始运行时由编译器分配的内存,它的分配是在程序开始编译时完成的,不占用CPU资源. 程序中的各种变量,在编译时系统已经为其分配了所需的内存空间,当该变量在作用域内使用 ...
- 【Visual Studio】简单内存泄漏检测方法 解决 Detected memory leaks! 问题(转)
原文转自 http://blog.csdn.net/u011430225/article/details/47840647 我的环境是: XP SP2.VS2003 最近在一个项目中, 程序退出后都出 ...
- 使用 Visual Studio 分析器找出应用程序瓶颈(转)
使用 Visual Studio 分析器找出应用程序瓶颈 Hari Pulapaka and Boris Vidolov 本文讨论: 以性能瓶颈为目标 应用程序代码分析 比较分析数据 性能报告 本文使 ...
- 使用 Visual Studio 分析器找出应用程序瓶颈
VS的性能分析工具 性能分析工具的选择 打开一个“性能分析”的会话:Debug->Start Diagnotic Tools Without Debugging(或按Alt+F2),VS2013 ...
- 在 Visual Studio 中安装 FxCop 分析器
本文转自 微软官网 : https://docs.microsoft.com/zh-cn/visualstudio/code-quality/install-fxcop-analyzers?view= ...
- Visual Studio 2022 预览版3 最新功能解说
我们很高兴地宣布Visual Studio 2022 的第三个预览版问世啦!预览版3 提供了更多关于个人和团队生产力.现代开发和持续创新等主题的新功能.在本文中,我们将重点介绍Visual Studi ...
随机推荐
- ibdata1是?
MySQL使用InnoDB引擎的时候,ibdata1这个文件会随着时间的增长,会变得越来越大,占据大量的磁盘空间. 那么,ibdata1里保存了哪些东西,为什么会变得越来越大呢,让我们开看看ibdat ...
- 重启Finder
解决Finder卡死的问题! 方法一:在Dock 图标上操作 按住 Option 键并右键点按 Finder 图标,选择菜单中的“重新开启” 方法二:在终端里操作 打开终端(应用程序 – 实用工具), ...
- 标准初始化css样式表
body { font-size:12px; line-height:1.3; font-family:'微软雅黑', Tahoma,Helvetica,Arial,'宋体', sans-serif; ...
- Oracle常用查看表结构命令
获取表: select table_name from user_tables; //当前用户的表 select table_name from all_tables; //所有用户的表 select ...
- oracle----修改表中的数据
1. 修改表中的数据:UPDATE语句: 语法: UPDTAE table_name SET column1 = value1,... [WHERE conditions] (2),无条件的更新(没有 ...
- sqlite优化记录:建立索引加快查询速度
凡是数据库中,索引的存在就是为了提高查询速度的,数据库的索引有点类似于书本上面的目录的概念,因为在英文中都是index,事实上也就是目录. 其算法应该叫做“倒排索引”,这个其实也类似于搜索引擎里面的基 ...
- POJ 2942 Knights of the Round Table(双连通分量)
http://poj.org/problem?id=2942 题意 :n个骑士举行圆桌会议,每次会议应至少3个骑士参加,且相互憎恨的骑士不能坐在圆桌旁的相邻位置.如果意见发生分歧,则需要举手表决,因此 ...
- [Gauss]POJ2065 SETI
题意: *代表0,a-z代表1-26 题目第三行给了一个公式 f (k) = $\sum\limits_{i=0}^{n-1} a_i k^i \pmod{P}$ {f(i)是输入的一串字符串中第i ...
- Web开发-表单验证
表单验证是Web开发中必不可少的一个环节,用来限制用户输入数据的规范和一致性.那么如何能够简化这一任务,让开发人员通过简单的属性设置就能达到目的呢? FineUI在这一点上也是下足了功夫,比Asp.N ...
- paip.无线路由器的无线接入WAN方式WDS设置大法
paip.无线路由器的无线接入WAN方式WDS设置大法 作者Attilax , EMAIL:1466519819@qq.com 来源:attilax的专栏 地址:http://blog.csdn. ...