.net - C++/cli 识别托管/非托管之间的转换并测量其成本

标签 .net performance visual-c++ c++-cli windbg

我对 C++/cli 还很陌生,并且在编写某些内容时并不总是确定我是否正在做一些在托管和非托管运行时之间创建转换的事情。例如,我无法添加 LARGE_INTEGER 或 std::vector 作为托管类的成员,但我可以在托管方法中间使用其中任何一个,但我不知道这样做是否会在托管和非托管之间创建转换运行时。我如何才能看到强制进行转换的每个点以及如何衡量这些转换的成本?

我想到的一种可能性是,我期望 Windows 中存在“过渡到非托管”和“过渡到托管”代码块。是否有可以放置断点的符号,例如使用windbg以便我可以看到每个转换?有没有办法让 Visual Studio 在运行时向您显示每个转换?

为了测量存在许多转换时的影响,是否有我可以使用 xperf 查看的 Windows 事件的相应事件跟踪,或者是否有我可以使用 perfmon 查看的性能计数器?

最佳答案

“非托管运行时”有点矛盾。非托管代码不在虚拟机中运行。另外,托管运行时本身就是非托管代码。我认为您对一般代码感兴趣,不仅仅是 CLR 和标准库,但最终一切都是 native 代码,其中一些是由 CLR JIT 创建的,其中一些是由 native 编译器创建的,但它们都是 native 代码到底。 .NET 和 native 异常甚至都有一个通用的异常处理模型 (SEH)(或更准确地说,.NET 使用操作系统提供的异常模型)。

JIT 运行后,没有太多托管->非托管转换的迹象,因为它们只是一个简单的函数调用(调试器可以分辨出差异,因为非托管代码位于 native 库的地址空间中,并且JIT 编译的托管代码位于 JIT 拥有的动态地址空间中)。反向方向稍微复杂一些,因为调用指令是在它调用的代码之前创建的,所以它必须是间接调用(通过函数指针)。但它仍然是一个直接指向 JIT 编译代码的指针,而不是指向某个可以放置断点的单个非托管->托管 thunk 的指针。实际上,函数指针可能一开始指向 JIT 本身,JIT 找出正在调用什么方法,编译它,更新函数指针,最后尾部调用到目的地,就像它首先被调用一样.

这就是 C++ 互操作的魔力。这也意味着托管->非托管转换实际上根本不值得担心。分析并找出哪些代码路径是昂贵的,如果结果是托管代码和非托管代码之间的调用,则对其进行优化。但不要随意寻找托管/非托管转换。

现在,您可能出于其他原因想要查找所有托管/非托管转换。例如,垃圾收集器可以中断任何运行托管代码的线程(同样,实际运行的代码是 native 代码,但 GC 可以识别它,因为它位于 JIT 使用的内存空间内,并且 JIT 生成的对象使用表详细说明了哪些内容)堆栈变量是任何给定指令指针处可到达的对象)。因此,如果您想保证某个线程永远不会被垃圾收集停止,您需要寻找并消除在该线程中运行的函数中的所有非托管->托管转换。即使有地方可以放置断点,断点注入(inject)仍然不是正确的方法,因为它只能捕获实际发生的转换,而不是有条件的转换。

关于.net - C++/cli 识别托管/非托管之间的转换并测量其成本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4216674/

相关文章:

javascript - 延迟解析 JavaScript - Google Page Speed

c++ - 在C/C++中快速读取多个文件的某些字节

performance - AS3-创建实例以访问方法/函数或使用静态[更新-一些基准测试-已添加]

c++ - msvc std::function 不接受带有嵌套 lambda 的通用 lambda

c# - 应用程序不会死于未处理的异常?

.net - 应用程序洞察 : loggerFactory. AddApplicationInsights 在 .net core 2.2.0 中已弃用

c# - .NET OneDrive Api 创建文件夹问题

.net - 在 VB.NET 的 IF 条件中执行赋值?

c++ - 使用虚拟继承和委托(delegate)构造函数在构造函数中崩溃

c# - C# 中的 read 和 readline 有什么区别?