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

Joh*_*son 2 .net performance windbg c++-cli visual-c++

我仍然是C++/cli的新手,并不总是确定我什么时候写一些东西是否正在做一些在托管和非托管运行时之间创建转换的东西.例如,我不能将LARGE_INTEGER或std :: vector添加为托管类的成员,但我可以在托管方法的中间使用,但我不知道这样做是否会在托管和非托管之间创建转换运行时间.如何看待我强制进行过渡的每个点,以及如何衡量这些过渡的成本?

我遇到的一种可能性是,我希望在Windows中存在"过渡到非托管"和"过渡到托管"代码块.那些我可以设置断点的符号,例如windbg,所以我可以看到每个转换?有没有办法让visual studio在运行时显示每个转换?

要在有许多转换的情况下测量inpact,是否有我可以用xperf看到的windows事件的相应事件跟踪,或者我可以用perfmon看到的性能计数器?

Ben*_*igt 6

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

在JIT运行之后,没有太多的managed-> unmanaged转换的迹象,因为它们只是一个简单的函数调用(调试器可以区分,因为非托管代码位于本机库的地址空间中,而JIT-编译的托管代码位于JIT拥有的动态地址空间中.反向方向稍微复杂一些,因为调用指令是在它调用的代码之前创建的,它必须是间接调用(通过函数指针).但它仍然是一个直接指向JIT编译代码的指针,而不是指向一个可以放置断点的单个非托管 - >托管thunk.实际上,函数指针可能从指向JIT本身开始,它指出正在调用的方法,编译它,更新函数指针,

这是C++互操作的神奇之处.这也意味着托管 - >非托管转换甚至不值得担心.配置文件并找出哪些代码路径是昂贵的,如果它是托管代码和非托管代码之间的调用,那么优化它.但是不要随意寻找托管/非托管转换.

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