共用方式為


iOS 和 Mac Catalyst 上的 Mono 解釋器

當您編譯適用於 iOS 或 Mac Catalyst 的 .NET 多平臺應用程式 UI (.NET MAUI) 應用程式時,編譯程式會將您的應用程式程式代碼轉換成Microsoft中繼語言 (MSIL)。 當您在模擬器或 Mac Catalyst 應用程式中執行 iOS 應用程式時,.NET Common Language Runtime (CLR) 會使用 Just in Time (JIT) 編譯程式編譯 MSIL。 在運行時間,MSIL 會編譯成機器碼,其可在應用程式的正確架構上執行。

不過,Apple 所設定的 iOS 安全性限制不允許在裝置上執行動態產生的程式代碼。 同樣地,在模擬器中的 ARM64 架構上執行的 iOS 應用程式中,不允許執行動態產生的程式代碼,以及在 ARM64 架構上執行的 Mac Catalyst 應用程式。 為了符合這項限制,iOS 和 Mac Catalyst 應用程式會使用「提前」(AOT)編譯程式來編譯 Managed 程式代碼。 這會產生可部署到 Apple 裝置或原生 Mac Catalyst 二進位檔的原生 iOS 二進位檔。

AOT 透過減少啟動時間,以及各種其他效能優化來提供優點。 不過,它也會限制某些功能,使其無法用於您的應用程式:

  • 有有限的泛型支援。 並非所有可能的泛型具現化都可以在編譯時期決定。 .NET MAUI 版本組建中遇到的許多 iOS 特定問題都是由於這項限制。
  • 不允許產生動態程序代碼。 這表示 System.Relection.Emit 無法使用,不支援 System.Runtime.Remoting,而且不允許使用 C# 動態 類型。

發生 AOT 限制時, System.ExecutionEngineException 將會擲回 訊息:「嘗試在僅限 AOT 模式中執行 JIT 編譯方法」。

Mono 解釋器克服這些限制,同時遵守平臺限制。 它可讓您在運行時間解譯應用程式的某些部分,而 AOT 則編譯其餘部分。 不過,在生產應用程式中使用解釋器有一些潛在的缺點:

  • 雖然應用程式大小通常會在啟用解釋器時大幅縮小,但在某些情況下,應用程式大小可能會增加。
  • 應用程式執行速度會變慢,因為解譯的程式代碼執行速度比 AOT 編譯的程式代碼慢。 此執行速度降低的範圍可以從無法測量到無法接受,因此應該執行效能測試。
  • 當機報表中的原生堆疊追蹤會變得不那麼有用,因為它們會包含來自解釋器的泛型框架,而解釋器不會提及正在執行的程序代碼。 不過,受控堆棧追蹤不會變更。

根據預設,.NET MAUI 偵錯組建會啟用解釋器,而且可以針對發行組建啟用。

提示

如果您的 .NET MAUI iOS 應用程式或 ARM64 型 Mac Catalyst 應用程式正常運作為偵錯組建,但當做發行組建當機,請嘗試為應用程式的發行組建啟用解釋器。 可能是您的應用程式或其其中一個連結庫會使用需要解釋器的功能。

啟用解釋器

您可以在 iOS 發行組建中開啟 Mono 解釋器,方法是在 .NET MAUI 應用程式的項目檔中將 MSBuild 屬性設定 $(UseInterpreter)true

<PropertyGroup Condition="$(TargetFramework.Contains('-ios')) and '$(Configuration)' == 'Release'">
    <UseInterpreter>true</UseInterpreter>
</PropertyGroup>

您也可以針對 ARM64 上的 Mac Catalyst 發行組建啟用解釋器:

<PropertyGroup Condition="'$(RuntimeIdentifier)' == 'maccatalyst-arm64' and '$(Configuration)' == 'Release'">
    <UseInterpreter>true</UseInterpreter>
</PropertyGroup>

警告

請勿在Android上啟用發行組建的解釋器,因為它會停用 JIT 編譯。

在 iOS 和 Mac Catalyst 上,您也可以使用 $(MtouchInterpreter) MSBuild 屬性來啟用解釋器。 這個屬性選擇性地接受要解譯之元件的逗號分隔清單。 此外, all 可以用來指定所有元件,而且當前面加上減號時,元件將會經過 AOT 編譯。 這可讓您:

  • 藉由指定 all 或 AOT 編譯所有元件,藉由指定 -all來解譯所有元件。
  • 藉由指定 MyAssembly 或 AOT 編譯個別元件,藉由指定 -MyAssembly 來解譯個別元件。
  • 混合和比對以解譯某些元件和 AOT 編譯其他元件。

警告

解釋器與原生 AOT 部署不相容,因此 $(UseInterpreter) $(MtouchInterpreter) 和 MSBuild 屬性在使用原生 AOT 時沒有作用。 如需詳細資訊,請參閱 原生 AOT 部署

下列範例示範如何解譯System.Xml.dll以外的所有元件:

<PropertyGroup Condition="$(TargetFramework.Contains('-ios')) and '$(Configuration)' == 'Release'">
    <!-- Interpret everything, except System.Xml.dll -->
    <MtouchInterpreter>all,-System.Xml</MtouchInterpreter>
</PropertyGroup>

下列範例示範如何編譯除了System.Numerics.dll以外的所有元件:

<PropertyGroup Condition="$(TargetFramework.Contains('-ios')) and '$(Configuration)' == 'Release'">
    <!-- AOT everything, except System.Numerics.dll, which will be interpreted -->
    <MtouchInterpreter>-all,System.Numerics</MtouchInterpreter>
</PropertyGroup>

重要

解釋器所執行的堆疊框架不會提供有用的資訊。 不過,因為解釋器可以根據每個元件停用,所以有可能讓某些元件中的堆疊框架正確描述於當機報表中。

或者,使用下列範例來編譯所有元件,同時仍允許解釋器執行動態程式代碼產生:

<PropertyGroup Condition="$(TargetFramework.Contains('-ios')) and '$(Configuration)' == 'Release'">
    <MtouchInterpreter>-all</MtouchInterpreter>
</PropertyGroup>

有時需要解釋器的另一個常見案例是在 ARM64 架構上執行的 .NET MAUI Mac Catalyst 應用程式,這可能會在啟動時擲回例外狀況。 啟用解釋器,通常可以修正此啟動例外狀況:

<PropertyGroup Condition="'$(RuntimeIdentifier)' == 'maccatalyst-arm64' and '$(Configuration)' == 'Release'">
    <MtouchInterpreter>-all,MyAssembly</MtouchInterpreter>
</PropertyGroup>