作者: OneAPM
查看: 2973|回复: 2
打印 上一主题 下一主题

[教程] 【Net Profiling】作为 .Net 攻城师,所必需掌握的 .Net Profiling ...

[复制链接]
跳转到指定楼层
楼主
OneAPM 发表于 2016-3-8 17:15:27 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
查看: 2973|回复: 2
标题:
作为 .Net 攻城师,所必需掌握的 .Net Profiling 技术

说明:
众所周知,性能问题是所有实用应用在迭代过程中必然要面对的问题。对于此类问题,简单地投入更多硬件资源的做法可能会取得一定效果。但总的来看,此类做法的边际成本是不断上升的。换言之,随着性能需求的上涨,要换取同样的性能提升,仅凭硬件升级所需要的成本会越来越高。故而性能优化是每一位运维/软件开发人员必须掌握的技术。

.Net Profiling
在进行应用性能优化实践时,首先面对的就是热点定位,即确定那些带来巨大资源耗散的代码位置。而在不借助外部工具的前提下,定位资源热点是一件相当困难的事。它需要当事人对于应用实现本身有一个整体的把握,了解应用架构内每一个功能模块代码的路径与细节。与此同时,当事人还要对于应用实现所依赖的第三方功能库的表现有一定的把握。对于那些具备一定规模的应用系统,具备前述素质的工程师的数量屈指可数。而即便是这些百里挑一的优秀人才,其热点预估也不能保证一定是准确的。
Profiling 技术 的提出正是为了解决热点定位而提出的,它以程序的实际运行数据来帮助工程师们来理解应用行为,极大地简化了工程师们的工作。而对于像 .Net 这样比较成熟的技术栈,专家们(如 Bill Chiles赵颉)都推荐工程人员通过实际的 Profiling 数据来定位性能瓶颈。实际操作中,获取 .Net Profiling 数据的功能被实现为一个被称为 Profiler 的 COM 组件实体。下文中,我们将就 Profiler 本身的实现进行一些探讨。

Profiling API
.Net Profiler 在本质上是 CLR 的一个插件,它通过应用 Profiling API 来保持与 CLR 的信息沟通,并以此获取到 .Net 应用的运行时数据。通常来说,Profiler 的实体都表现为一个动态链接库(即 .dll 文件),CLR 在运行时会去加载该库(CLR 加载 Profiler 的详细配置可以参考 这篇文档),并在程序运行的特定阶段向库发送信息并接受库所返回的信息。
需要特别强调的一点是,虽然被称作是 Profiling API,但 CLR 的这套接口能做的可不仅仅是简单地度量应用的运行时间和内存耗散。实践上,profiling API 能够完成诸如代码覆盖、运行时插入等许多高级功能。不过,正如 MSDN Profiling 综述文档 所强调的,Profiling 对于应用本身应该透明。也就是说,在编写应用的时候,开发人员不应该在自己的逻辑中依赖 Profiler 或者被其影响。
对于 .Net 技术栈而言,由于环境本身引入了 application domain, GC, managed exception handling, JIT 等高级特性,Profiling 所展现的就不能仅止于应用运行所消耗的时间或者内存。为了能够真正地表现出运行时行为,Profiling API 中提供了包含这些特性的数据的接口。这就使得 Profiling API 在设计并不是如很多人想得那样直观。
常见的 .Net Profiler 实现多采取如下架构:

.Net Profiler 架构
其中,ICorProfilerCallbackICorProfilerInfo 就是 Profiling API 中最常被应用到的两个。在应用运行时,Profiler DLL 会被加载到应用所在的进程中。通过实现 ICorProfilerCallback 下特定功能的接口,Profiler DLL 会在应用运行时收到相关的动作执行通知。例如,如果在 Profiler DLL 中实现了 ICorProfilerCallback::AssemblyLoadFinished 接口,那么在应用运行中每加载完一个程序集 时,Profiler DLL 中该接口的实现代码就会被调用。与此类似,Profiler DLL 可以靠实现 ICorProfilerInfo 下的接口来完成对被监测应用状态的获取。
需要补充说明一点,上文所说的 ICorProfilerCallback 接口实际上存在有 ICorProfilerCallback ~ ICorProfilerCallback7 这样7个版本的接口定义。高标号的接口版本向下兼容,但会提供新的功能扩展。不过,更高标号的接口往往也需要有更新版本的 CLR 来支持(如调用 ICorProfilerCallback7 需要在环境中部署 .Net Framework 4.6.1 以上版本),在实际使用时需要多加注意。
目前,Profiling API 可以被任何非托管的 COM 兼容的语言所调用。另外,API 本身的实现非常高效的,不会带来大到足以导致 profiling 失效的额外性能负担。也正因此,基于 Profiling API 完全可以实现一个抽样 profiler(对于 profiling 模式的探讨可参照 这篇文献 的 2.1 章节内容)。

目前 Profiling API 所支持的特性
正如前文所述,Profiler 对于程序行为的描述源自 profiling API 所提供的信息。在目前版本中,凭借 profiling API 能够获取到下列事件的消息通知:
  • CLR 的启动与关停
  • application domain 的创建与关闭
  • 程序集的加载与卸载
  • 模块(Module)的加载与卸载
  • COM vtable 的创建与销毁
  • JIT 编译与 code-pitching 的出发
  • 类的加载卸载
  • 线程的创建与销毁
  • 函数的进入与返回
  • 托管代码与非托管代码的执行切换
  • 运行时挂起
  • 运行时堆内存信息与 GC 活动
随着 .Net 技术的演进,未来的 Profiling API 或许能够提供更多的信息。不过,以下功能点是 Profiling API 不会实现的,请在应用时回避:
  • 非托管代码的执行信息
  • 运行时修改自身代码的应用的 Profiling(如 AOP)
  • 边界检验
  • 远程 profiling
  • 高可靠性环境下的 profiling
其他需要留意之处
前文强调过,Profiler 是一个非托管的 DLL 库,会在应用运行时被加载到 CLR 中并与应用处于同一进程空间下。如此,Profiler DLL 实质上是不受托管代码的访问控制的。其运行唯一的限制就是运行 Profiler 的 OS 用户必须拥有足够权限。因此,对于要部署 Profiler 的技术人员来说,必须要明白这其中可能的风险,提早进行准备。例如可以把 Profiler DLL 加到访问控制列表(ACL)中以免恶意用户对其加以利用。
还有,Profiler DLL 作为 CLR 的一个插件,其运行错误可能会引起 CLR 本身的崩溃,在实施时一定要足够小心。而对于那些运行在栈内存空间紧张的环境下的 Profiler,要警惕因为 ICorProfilerCallback 导致栈溢出而引起的应用崩溃。在这种资源受限的环境中,要尽可能地减少 Profiler 自身的资源耗散。尽力避免原本能够运行的应用因为 Profiler 而导致无法运行的情况。

结语
本文简述了 .Net Profiling 技术的总体情况,并就其中的一些重要技术点进行了阐述。希望能帮助读者初步理解 .Net Profiling 技术。后续,我们将具体到代码实施层面,就 .Net Profiling 的实现进行详细讨论
OneAPM 助您轻松锁定 .NET 应用性能瓶颈,通过强大的 Trace 记录逐层分析,直至锁定行级问题代码。以用户角度展示系统响应速度,以地域和浏览器维度统计用户使用情况。想阅读更多技术文章,请访问 OneAPM 官方博客
本文转自 OneAPM 官方博客

评分

参与人数 1金钱 +3 收起 理由
乔克斯 + 3 感谢分享,LZ辛苦了~

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏1 转播转播
回复 论坛版权

使用道具 举报

沙发
乔克斯 发表于 2016-3-8 18:05:01 | 只看该作者
帖子已排版。。老实说。。你发的几个贴我都看不懂。。。
板凳
贱贱的贱贱 发表于 2016-3-8 23:08:07 | 只看该作者
乔克斯 发表于 2016-3-8 18:05
帖子已排版。。老实说。。你发的几个贴我都看不懂。。。

转载自segmentfault
您需要登录后才可以回帖 登录 | 加入CSkin博客

本版积分规则

QQ|申请友链|小黑屋|手机版|Archiver|CSkin ( 粤ICP备13070794号

Powered by Discuz! X3.2  © 2001-2013 Comsenz Inc.  Designed by ARTERY.cn
GMT+8, 2024-11-26 00:11, Processed in 0.633887 second(s), 30 queries , Gzip On.

快速回复 返回顶部 返回列表