「非託管運行時」有點矛盾。非託管代碼不會在虛擬機中運行。另外,託管運行時本身也是非託管代碼。我認爲你一般對代碼感興趣,不僅僅是CLR和標準庫,但最終一切都是本地代碼,其中一些是由CLR JIT創建的,其中一些是由本地編譯器創建的,但它都是本機代碼到底。甚至有一個針對.NET和本機異常(或更確切地說,.NET使用操作系統提供的異常模型)的通用異常處理模型(SEH)。
JIT運行後,沒有太多的託管 - >非託管轉換的跡象,因爲它們只是一個簡單的函數調用(調試器可以區分不同的代碼,因爲非託管代碼位於本地庫的地址空間中,並且JIT編譯的託管代碼位於JIT擁有的動態地址空間中)。由於調用指令是在它調用的代碼之前創建的,它必須是一個間接調用(通過函數指針),所以涉及的方向相反。但它仍然是一個指向JIT編譯代碼的指針,而不是一個單獨的非託管的>管理的thunk,您可以在其中放置一個斷點。實際上,函數指針可能開始指向JIT本身,該指針指出正在調用的方法,編譯它,更新函數指針,並最終對目標進行尾部調用,就像它首先被調用一樣。
這是C++ interop的神奇之處。這也意味着託管式和非託管式轉換實在不值得擔憂。配置文件並找出哪些代碼路徑非常昂貴,如果事實證明是託管代碼與非託管代碼之間的調用,則優化它。但不要隨意尋找託管/非託管轉換。
現在,有一個你可能想看看所有的託管/非託管過渡之外的原因。例如,垃圾收集器可以中斷運行託管代碼的任何線程(同樣,實際運行的代碼是本地代碼,但GC可以識別它,因爲它位於JIT使用的內存空間內部,JIT生成的對象使用表詳細說明了什麼堆棧變量在任何給定的指令指針處都是可達的對象)。所以如果你想保證某個線程永遠不會被垃圾回收所阻擋,你需要搜索並消除在該線程中運行的函數中的所有非託管 - >受管理的轉換。即使有地方放置斷點,斷點注入仍然不是正確的方法,因爲它只捕獲實際進行的轉換,而不是那些有條件的轉換。
非常有趣。從JITed託管代碼調用本地代碼在運行時是不可見的(儘管可能有一些必須包含的堆棧fanangling?)。 – 2010-11-18 19:21:50