2016 年 3 月

第 31 卷,第 3 期

本文章是由機器翻譯。

編譯器 - 使用背景 JIT 管理特性指引最佳化

Hadi Brais |2016 年 3 月

由編譯器執行某些效能最佳化作業都很好。也就是說,無論實際的程式碼取得執行階段執行,最佳化會改善效能。為例,迴圈 unrolling 若要啟用向量化。此迴圈,因此,而不是單一迴圈的主體中執行單一作業設定 (例如新增兩個整數儲存在不同的陣列),運算元的值相同的作業會在多組運算元同時執行的最佳化轉換 (新增四個整數配對)。

相反地,有極重要的最佳化,編譯器會執行啟發。也就是說,編譯器不確定,這些最佳化實際上的運作很好的執行階段執行的程式碼。兩個最重要的最佳化,屬於這個類別 (或可能在所有類別目錄之間) 是暫存器配置和函式內嵌。有助於做出更佳決策,執行這種最佳化執行其中一個應用程式時,編譯器或執行多次,並提供與一般使用者輸入時同時錄製哪一個程式碼。

收集有關執行的應用程式的資訊稱為設定檔。編譯器接著可以使用此設定檔来將某些及其最佳化更有效率,有時會造成顯著的加速效果。這項技術稱為 「 特性指引最佳化 (PGO) 」。您應該使用這項技術,當您撰寫可讀取和可維護的程式碼,採用良好的演算法、 最大化資料存取的位置、 鎖定爭用降至最低並開啟所有可能的編譯器最佳化作業,但仍不滿意得到的效能。一般而言,PGO 可以用來改善程式碼,而不只是效能的其他特性。不過,本文所討論的技巧可以用來只會提高效能。

我所討論中詳細說明 Microsoft Visual c + + 編譯器在前一篇文章中的原生 PGO msdn.com/magazine/mt422584。人閱讀該文章,我有一些很棒的消息。使用 managed 的 PGO 會比較簡單。特別是,我接下來要討論這篇文章中的功能,也就是背景 JIT (也稱為多核心 JIT) 是簡化許多。不過,這是進階的文章。CLR 團隊曾寫過簡介的部落格文章三年前 (bit.ly/1ZnIj9y)。Microsoft.NET Framework 4.5 和所有更新版本中支援背景 JIT。

有三個受管理的 PGO 技巧 ︰

  • 編譯使用 Ngen.exe (稱為 preJIT 的程序) 的二進位程式碼的 managed 程式碼,然後使用 Mpgo.exe 來產生代表可用來使效能最佳化的二進位程式碼的常見使用案例的設定檔。這是原生 PGO 類似。我會把這項技術稱為靜態 MPGO。
  • 第一次中繼語言 (IL) 方法是關於是 JIT 編譯,產生檢測的二進位程式碼會記錄在執行階段組件的方法開始執行哪些資訊。然後稍後再使用該記憶體中設定檔重新編譯 JIT 編譯的 IL 方法來產生高度最佳化的二進位程式碼。這也是類似於原生 PGO 不同之處在於一切都會在執行階段。我會把這項技術稱為動態 MPGO。
  • 使用背景 JIT 來隱藏儘可能以 jit 編譯,以智慧方式 jit 編譯 IL 方法,其實際執行第一次之前的額外負荷。在理想情況下,第一次呼叫方法時,它已經本人 JIT 編譯,並會有不需要等到 JIT 編譯器編譯的方法。

有趣的是,這些技巧有導入.NET Framework 4.5 和更新版本也支援。靜態 MPGO 只適用於由 Ngen.exe 產生的原生映像。相反地,動態 MPGO 只適用於 IL 方法。可能的話,使用 Ngen.exe 產生原生映像,並將它們最佳化會使用靜態 MPGO,因為這項技術是簡單許多,而在此同時,它提供不錯的加速效果。第三項技巧,背景 JIT,是與前兩個非常不同,因為它可減少 JIT 編譯而不提升的效能產生的二進位程式碼的額外負荷,因此,可搭配其他兩個技術。不過,使用 JIT 單獨有時候很有幫助,改善應用程式啟動或特定的常見使用案例的效能高達 50%的背景,這是很好。這篇文章著重於背景 JIT。在下一節中,我將討論 JIT 編譯的 IL 方法,它會如何影響效能的傳統方式。然後我會討論背景 JIT 的運作方式、 為何有用的方式以及如何正確使用它。

傳統的 JIT

您可能已經有基本的概念,因為有許多文章討論此程序,.NET JIT 編譯器的運作方式。不過,我想要再次造訪這個主題進行更詳盡而且精確度 (但不是多) 到背景 JIT,以便您可以輕鬆地取得之前遵循下一節,以及確實了解功能。

在顯示的範例,請考慮 [圖 1。T0 是主要執行緒。執行緒的綠色部份表示執行緒正在執行應用程式程式碼,它以全速執行。讓我們假設 T0 正在執行中已被 JIT 編譯的 (最上層綠色的一部分),而且呼叫 IL 方法 M0 的下一個指令的方法。由於 M0 會執行第一次,而且它以 IL,其編譯為二進位,處理器可以執行的程式碼。基於這個理由,當執行呼叫指令時,呼叫函式稱為 JIT IL 虛設常式。此函式最後呼叫 JIT 編譯器以 jit 編譯的 M0 IL 程式碼,並傳回產生的二進位程式碼的位址。這項工作無關的應用程式本身,而由紅色 T0 部分表示它是額外負荷。幸運的是,儲存 JIT IL 虛設常式的位址的記憶體位置將會修補與對應的二進位程式碼的位址,以便以全速執行的相同的函式的後續呼叫。

傳統 JIT 執行時的額外負荷 Managed 程式碼
[圖 1 傳統 JIT 執行時的額外負荷 Managed 程式碼

現在,傳回從 M0 之後, 執行其他一些已被 JIT 編譯的程式碼,並再 IL M1 呼叫方法。就像使用 M0,稱為 JIT IL 虛設常式,其中依序呼叫 JIT 編譯器編譯的方法,並傳回二進位程式碼的位址。傳回從 M1 之後, 會執行一些二進位程式碼和兩個多個執行緒,T1 和 T2,再開始執行。這是變得有趣。

在執行後已經被 JIT 編譯的方法,T1 和 T2 要呼叫的 IL 方法 M3,從未之前呼叫,因此,必須是 JIT 編譯。就內部而言,JIT 編譯器會維護一份所有被 JIT 編譯的方法。會列出每個 AppDomain 和一個共用的程式碼。這份清單由鎖定保護,以及每個項目也會保護它自己的鎖定,讓多個執行緒可以安全地進行 JIT 編譯同時。在此情況下會發生什麼情況是,一個執行緒,假設 T1,會是 JIT 編譯方法和浪費時間執行的工作,而 T2 會執行任何動作,與該應用程式無關 — 正在等待鎖定只因為它實際上有沒有 — M3 二進位碼等到可以使用。在此同時,T0 會編譯 M2。當執行緒完成 JIT 編譯方法時,它的二進位程式碼位址取代 JIT IL 虛設常式的位址、 解除鎖定和執行方法。請注意,T2 會最後喚醒只是執行 M3。

這些執行緒來執行的程式碼的其餘部分會顯示綠色列在 [圖 1。這表示應用程式以全速執行。即使新的執行緒,T3,開始執行,它需要執行的所有方法都已經 JIT 編譯,因此,它也會執行完整的速度。產生的效能變得非常接近原生程式碼的效能。

大致來說,每個這些紅色區段的持續時間主要取決於以 jit 編譯的方法,依序取決於如何大型且複雜的方法是所需的時間量。它可以上萬毫秒 (不包括任何必要的組件或模組的載入時間) 的範圍從幾個百萬分之一秒為單位。如果在啟動應用程式需要執行第一個時間少於一百個方法,並不困難。但它需要執行第一次數百或數千個方法,如果紅色的 [所有產生的影響區段可能會很大,尤其是當花費的時間以 jit 編譯方法相當的時間花費執行方法,這會導致兩百分比降低。例如,如果應用程式需要執行一千個不同的方法,使用 3 毫秒為單位平均 JIT 時間啟動時,可能要花費 3 秒內完成啟動。這是什麼大不了的事。因為無法滿足您的客戶不適合的商務。

請注意,可能會有一個以上同時執行緒 JIT 編譯的相同方法。您也可 JIT 的第一次嘗試失敗,但第二個會成功。最後,還有可能已被 JIT 編譯的方法是重新編譯 JIT 編譯。不過,所有這些情況下已超出本文的範圍,而且您不需要使用背景 JIT 時要了解。

背景 JIT

無法避免或大幅降低 JIT 編譯上一節中所討論的負擔。您不必 JIT IL 方法來執行它們。您可以做什麼,不過,會變更這項額外工作所產生的時間。重要的觀念是,而不是等待 IL 来呼叫的方法第一次以 jit 編譯它,您可以 JIT 稍早該方法,讓呼叫它時,二進位碼已經產生。如果您說得沒錯,所示的所有執行緒 [圖 1會是綠色而且會將所有在執行完整的速度,如同執行 NGEN 原生映像,或者可能會導致更好的。但是你之前,必須處理兩個問題。

第一個問題是,如果您打算以 jit 編譯方法之前就,哪一個執行緒是以 jit 編譯它嗎? 您不難看出解決此問題的最佳方式是將專用的執行緒執行的背景和 JIT 方法可能會盡快執行。因此,這僅適用於至少兩個核心可以使用 (幾乎都是如此),因此 JIT 編譯負擔隱藏的重疊執行的應用程式的程式碼。

第二個問題是 ︰ 如何知道哪一種方法以 jit 編譯接下來會在第一次呼叫前? 請記住,通常每個方法中有條件式方法呼叫,因此您不能只 JIT 可能呼叫或在接下來選擇以 jit 編譯的方法太推測式的所有方法。就很可能是 JIT 背景執行緒很快落後應用程式執行緒。這是在設定檔派上用場。您第一次執行應用程式和任何的常見使用案例和方法都是 JIT 編譯的記錄順序一樣 JIT 編譯每個案例的個別的啟動。然後您可以發行記錄的設定檔與應用程式,以便當使用者的電腦上執行時,JIT 編譯負擔會降到最低方面時鐘的時間 (這是使用者感知到時間與效能)。這項功能稱為背景 JIT 並使用非常輕輕鬆鬆從您的側邊。

在前一節中,您會看到 JIT 編譯器如何可以在不同的執行緒平行 JIT 編譯不同方法。嚴格來說,已經是多核心的傳統的 JIT。很不幸且令人困惑的 MSDN 文件參考的功能為多核心 JIT 的至少兩個核心的需求,而不是根據其定義的特性。我正在使用名稱 「 背景 JIT 」,因為這是我想要散佈。PerfView 的內建支援此功能,並使用名稱背景 JIT。請注意,名稱為 「 多核心 JIT 」 供 Microsoft 用在開發初期的名稱。本章節的其餘部分,我將討論您只需要在您的程式碼和它的變化傳統 JIT 模型上套用這項技術。我也會告訴您如何使用 PerfView 來測量背景 JIT 的好處,當您使用自己的應用程式上。

若要使用背景 JIT,您需要告知執行階段設定檔 (一個用於每個 JIT 編譯的觸發程序的案例) 的存放位置。您也需要告知執行階段使用,因此它會讀取設定檔,以判斷要在背景執行緒上編譯方法的設定檔。這當然,有相關聯的使用方式情節啟動之前,足以完成。

若要指定要放置設定檔的位置,呼叫 System.Runtime.ProfileOptimization.SetProfileRoot 方法在 mscorlib.dll 中定義。這個方法看起來像這樣 ︰

public static void SetProfileRoot(string directoryPath);

其唯一參數 directoryPath,目的是資料夾的指定中的所有設定檔將會讀取或寫入的目錄。只有第一個呼叫相同的 AppDomain 中,這個方法才會生效,而且其他任何呼叫都會被忽略 (不過,相同的路徑可以由不同的 Appdomain)。此外,如果電腦沒有至少兩個核心,就會忽略 SetProfileRoot 的任何呼叫。唯一的這個方法就是一個內部變數中儲存指定的目錄,以便稍後必要時,才能使用。這個方法通常稱為可執行檔 (。EXE) 的初始化期間的程序。共用程式庫不應該呼叫它。您可以此方法每次呼叫的應用程式執行時,但在 ProfileOptimization.StartProfile 方法的任何呼叫之前。這個其他方法看起來像這樣 ︰

public static void StartProfile(string profile);

應用程式来瀏覽執行路徑,因此您想要最佳化 (例如啟動後) 其效能時,呼叫這個方法並傳遞給它的檔案名稱和設定檔的副檔名。如果檔案不存在,設定檔記錄,並儲存在檔案中具有指定名稱使用 SetProfileRoot,您所指定的資料夾中。此程序稱為 「 設定檔的記錄 」。 如果指定的檔案存在,且包含有效的背景 JIT 設定檔,背景 JIT 生效專用的背景執行緒 JIT 編譯方法,選擇根據設定檔表示。此程序稱為 「 設定檔扮演 」。 雖然播放設定檔,應用程式所展現的行為仍然會記錄,且會取代相同的輸入設定檔。

您無法播放的設定檔,而不進行錄製。目前不支援。您可以呼叫的 StartProfile 多次指定不同的設定檔適用於不同的執行路徑。如果設定檔的根目錄使用 SetProfileRoot 之前,請先呼叫之後,這個方法沒有任何作用。此外,這兩種方法有任何作用,如果指定的引數是以任何方式不正確。事實上,這些方法不會擲回任何例外狀況或傳回錯誤碼至任何非預期的方式不會影響應用程式的行為。兩者都是安全執行緒,就像其他每個靜態方法,framework 中一樣。

例如,如果您想要改善啟動效能,第一個步驟中的 main 函式呼叫這兩個方法。如果您想要改善效能的特定使用案例,當使用者預期要起始這種情況下,任何時候前面呼叫 SetProfileRoot 呼叫 StartProfile。請記住,所有項目在本機中發生的 Appdomain。

這是您只需要使用您的程式碼中的背景 JIT。很簡單,您也可以只嘗試而不考慮有關是否這是很有用或沒有太多。然後,您可以測量來判斷是否值得維持所取得的加速效果。如果至少百分之 15 加速的效果,您必須保留此資源。否則,就是您的呼叫。現在我會詳細解釋它的運作方式。

每次呼叫 StartProfile 時,程式碼目前執行所在之 appdomain 的內容中執行下列動作 ︰

  1. 包含設定檔 (如果有的話) 的檔案的所有內容會都複製到記憶體中。然後關閉檔案。
  2. 如果這不是第一次成功呼叫 StartProfile,已經有背景 JIT 執行緒執行。在此情況下,它就會終止,並建立新的背景執行緒。然後呼叫 StartProfile 傳回給呼叫者。
  3. 此步驟會在幕後 JIT 執行緒執行。設定檔會剖析。錄製的方法都是 JIT 編譯的循序和盡快地記錄它們的順序。此步驟會構成播放程序的設定檔。

這是它就而言背景執行緒。如果它已完成 JIT 編譯所有記錄的方法,它會以無訊息方式終止。如果發生任何錯誤時剖析或 JIT 編譯方法,會以無訊息方式結束執行緒。如果組件或模組,尚未載入,而且需要以 jit 編譯方法,將不會載入,因此這個方法將無法 JIT 編譯。背景 JIT 設計,讓它不會變更程式儘可能的行為。載入模組時,會執行其建構函式。此外,當找不到模組,會呼叫 System.Reflection.Assembly.ModuleResolve 事件註冊的回呼。因此,如果背景執行緒否則會比先前載入的模組,這些函式的行為可能會變更。這同樣適用於向 System.AppDomain.AssemblyLoad 事件回呼。背景 JIT 時不會載入它需要的模組,因為它可能無法編譯錄製的方法,導致不太大的好處。

您可能會好奇,為什麼不建立多個背景執行緒以 jit 編譯方法? 嗯,首先,這些執行緒會需要大量計算的因此與應用程式執行緒可能會爭用。第二,多個這些執行緒表示多個執行緒同步處理爭用。第三,不太可能取得 JIT 編譯方法,但從不會被呼叫的任何應用程式執行緒。相反地,可能會取得第一次,甚至不會記錄在設定檔或然後再以 JIT 編譯多核心的執行緒所呼叫的方法。由於這些問題,有一個以上的背景執行緒可能不是很有幫助。不過,CLR 團隊可以這樣將來 (尤其是當可放寬載入模組的限制)。現在就來探討包括記錄程序的設定檔的應用程式執行緒的時間。

[圖 2 顯示相同的範例中為 [圖 1 不同之處在於背景是 JIT 啟用。亦即會在背景執行緒 JIT 編譯方法 M0、 M1、 M3 和 M2,依序。請注意這個背景執行緒的應用程式執行緒 T0、 T1、 T2 和 T3 針對如何互相競爭。背景執行緒都以 jit 編譯每個方法以滿足其目的任何執行緒呼叫第一次。下面的討論假定這是寫 M0、 M1 和 M3,但與 M2 不太對。

範例,顯示背景 JIT 最佳化,相較於 [圖 1
[圖 2 範例,顯示背景 JIT 最佳化,相較於 [圖 1

即將呼叫 M0 T0 時,背景 JIT 執行緒已編譯 JIT。不過,方法位址並未尚未修補和仍然指向 JIT IL 虛設常式。背景 JIT 執行緒可能已修正的項目,但它不會以稍後判斷是否已呼叫方法。這項資訊由 CLR 團隊用於評估背景 JIT。因此,JIT IL 虛設常式會呼叫,會看到方法,已編譯的背景執行緒上。它唯一必須做的作法就是修補程式的位址,並執行方法。請注意如何 JIT 編譯負擔完全排除在此執行緒。M1 接收相同的處理方式 T0 上被呼叫時。M3 接收相同的處理方式,在 T1 上呼叫時。但是,當 T2 呼叫 M3 (請參閱 [圖 1) 方法位址已修補 t1 很快,因此它直接呼叫方法的實際二進位程式碼。然後 T0 呼叫 M2。不過,背景執行緒 JIT 尚未完成,但 JIT 編譯方法,進而 T0 等候 JIT 鎖定的方法。JIT 編譯方法時,T0 喚醒並呼叫它。

我還沒討論的方法取得設定檔中記錄的方式。它也是很有可能應用程式執行緒呼叫,背景執行緒 JIT 尚未甚至開始 JIT 編譯的方法 (或永遠不會將 JIT 它因為它不是在設定檔)。我已編譯的靜態或動態的 IL 方法尚未被 JIT 編譯下列演算法中呼叫時,如果應用程式執行緒上執行的步驟 ︰

  1. 取得方法所在之 appdomain JIT 清單鎖定。
  2. 如果已由其他應用程式執行緒產生的二進位程式碼,鎖定 JIT 清單,並移至步驟 13。
  3. 將新的項目加入至清單代表 JIT 背景工作的方法,如果不存在。如果已經存在,就會遞增參考計數。
  4. 釋放 JIT 清單鎖定。
  5. 取得 JIT 鎖定的方法。
  6. 如果已由其他應用程式執行緒產生二進位碼,請移至步驟 11。
  7. 如果此方法不支援背景 JIT,略過此步驟。目前,JIT 支援只以靜態方式的背景,就發出與 System.Reflection.Assembly.Load 尚未載入的組件中所定義的 IL 方法。現在如果支援的方法,請檢查是否已由背景執行緒 JIT 編譯的 JIT。如果這種情況,記錄的方法,然後移至步驟 9。否則,請移至下一個步驟。
  8. JIT 的方法。JIT 編譯器會檢查方法的 IL,決定所有必要的型別,可確保所有必要的組件會載入並建立所有必要的型別物件。如果發生任何錯誤,則會擲回例外狀況。此步驟會引發大部分的額外負荷。
  9. 實際的二進位程式碼之方法的位址來取代 JIT IL 虛設常式的位址。
  10. 如果方法已被 JIT 編譯的應用程式執行緒,而不是背景執行緒 JIT,沒有使用中的背景 JIT 錄製器和背景 JIT; 支援的方法此方法會記錄在記憶體中設定檔。設定檔中維護的方法都是 JIT 編譯的順序。請注意,不會記錄產生的二進位程式碼。
  11. 釋放 JIT 鎖定的方法。
  12. 安全地降低使用的清單鎖定方法的參考計數。如果它成為零,會移除項目。
  13. 執行這個方法。

發生任何下列情況時,就會結束背景 JIT 記錄程序 ︰

  • 與背景 JIT 管理員相關聯的 AppDomain 由於任何原因而卸載。
  • StartProfile 會再次呼叫相同的 AppDomain 中。
  • 方法都是 JIT 編譯的應用程式執行緒中的速度變得非常小。這表示應用程式達到穩定的狀態,它幾乎不需要 JIT 編譯。取得之後此點不感興趣背景 JIT 編譯的 JIT 的任何方法。
  • 已達到其中一個記錄限制。模組的數目上限為 512、 方法的最大數目為 16384 和錄製最長持續期間為一分鐘。

在記錄程序終止時,記錄中的記憶體設定檔會傾印到指定的檔案。如此一來,的下次執行應用程式,它會反映在其上一次執行應用程式所展現的行為的設定檔。前面提過之前,一定會覆寫設定檔。如果您想要保留目前的設定檔,您必須手動進行呼叫 StartProfile 之前的複本。設定檔的大小通常不會超過數千數十個位元組。

在關閉之前這一節,我想要談選取設定檔的根項目。用戶端應用程式,您可以指定的特定使用者或應用程式相對目錄,根據您要有不同的設定檔針對不同的使用者或僅有一組的所有使用者設定檔。針對 ASP.NET 和 Silverlight 應用程式,您將可能使用應用程式相對目錄。事實上,從 ASP.NET 4.5 和 Silverlight 4.5 開始,預設值和設定檔會啟用 JIT 的背景會儲存應用程式旁邊。執行階段的行為模式,如同您呼叫了 SetProfileRoot 和 StartProfile main 方法中,因此您不必執行任何動作來使用的功能。您仍然可以呼叫 StartProfile,不過,如先前所述。您可以關閉自動背景 JIT.NET 部落格文章,< 簡單方案的改善應用程式啟動效能 > 中所述,profileGuidedOptimizations 旗標設定為 [Web 組態檔中的 [無 (bit.ly/1ZnIj9y)。這個旗標可能只有一個其他值,也就是全部],這可讓背景 JIT (預設值)。

背景 JIT 作用中

背景 JIT 就是事件追蹤的 Windows (ETW) 提供者。也就是說,它會報告的這項功能,例如 Windows 效能錄製器和 PerfView ETW 消費者相關的事件數目。這些事件可讓您診斷任何不足或發生在 JIT 背景的失敗。特別是,您可以判斷多少方法所編譯的背景執行緒和總 JIT 時間的方法。您可以下載從 PerfView bit.ly/1PpJUpv (沒有安裝所需,只解壓縮及執行)。我將示範使用下列簡單程式碼 ︰

class Program {
  const int OneSecond = 1000;
  static void PrintHelloWorld() {
    Console.WriteLine("Hello, World!");
  }
  static void Main() {
    ProfileOptimization.SetProfileRoot(@"C:\Users\Hadi\Desktop");
    ProfileOptimization.StartProfile("HelloWorld Profile");
    Thread.Sleep(OneSecond);
    PrintHelloWorld();
  }
}

Main 函式,呼叫 SetProfileRoot 和 StartProfile 設定背景 JIT。在執行緒進入睡眠大約 1 秒,然後呼叫的方法,PrintHelloWorld。這個方法只會呼叫 Console.WriteLine,並傳回。編譯此程式碼以 IL 可執行檔。請注意 Console.WriteLined 不需要 JIT 編譯,因為它已編譯使用 NGEN 時在電腦上安裝.NET Framework。

使用 PerfView 來啟動和設定檔可執行檔 (如需有關如何執行這些作業的詳細資訊,請參閱.NET 部落格文章,「 您的應用程式使用改善效能 PerfView,「 在 bit.ly/1nabIYC, ,或在通道 9 PerfView 教學課程 bit.ly/23fwp6r)。請記得檢查背景 JIT 核取方塊 (在.NET Framework 4.5 和 4.5.1 中的必要項) 若要啟用這項功能的擷取事件。等待直到 PerfView 完成,然後開啟 JITStats] 頁面 (請參閱 [圖 3);PerfView 會告訴您此程序不會使用背景 JIT 編譯。這是因為第一次執行中,設定檔具有產生。

JITStats 在 PerfView 中的位置
[圖 3 JITStats 在 PerfView 中的位置

因此,現在您已經產生 JIT 設定檔的背景,請使用 PerfView 來啟動和設定檔可執行檔。此時,不過,當您開啟 [JITStats] 頁面上,您會看到的其中一個方法,也就是 PrintHelloWorld 為 JIT 編譯 JIT 背景執行緒,但不是一種方法,也就是主要。它也會告訴您大約 92%的 JIT 編譯所有 IL 方法所花費的時間發生在應用程式執行緒。PerfView 報表也會顯示一份所有方法都是 JIT 編譯,IL 和每個方法,JIT 編譯的二進位大小的方法,以及其他資訊。您可以輕鬆存取整組背景 JIT 事件的相關資訊。不過,這裡的空間不足,我將不會進入詳細資料。

您可能會好奇用途的大約 1 秒,睡眠狀態相關。這是所需的 PrintHelloWorld JIT 編譯的背景執行緒上。否則,很可能在應用程式執行緒,會啟動編譯背景執行緒之前的方法。換句話說,您必須呼叫 StartProfile 早期,讓背景執行緒可以超越大部分的情況。

總結

背景 JIT 就是在.NET Framework 4.5 及更新版本支援的特性指引最佳化。這篇文章討論幾乎所有動作都想要知道有關這項功能。我已經示範過為什麼需要這項最佳化、 運作方式以及如何適當使用太多程式碼中。NGEN 不方便或不可能時,請使用此功能。由於很容易使用,您也可以只嘗試而不考慮是否它就有幫助您的應用程式不需太多。如果您滿意所取得的加速效果,讓它。否則,您可以輕鬆地移除它。Microsoft 會用來改善啟動效能,其應用程式的一些背景 JIT。我希望您可以有效地使用它在應用程式,來達成顯著的啟動 JIT 廣泛的使用方式案例和應用程式啟動的加速效果。


Hadi Brais是教育部登記學者在印度協會的技術 Delhi,研究下一代的記憶體技術的編譯器最佳化作業。他花大部分時間撰寫程式碼,在 C / C + + /cli C# 和深入探討深度執行階段、 編譯器架構和電腦架構。他的部落格網址 hadibrais.wordpress.com。與他連絡 hadi.b@live.com

感謝以下的微軟技術專家對本文的審閱: Vance Morrison