次の方法で共有


iOS および Mac Catalyst での Mono インタープリター

iOS または Mac Catalyst 用の .NET マルチプラットフォーム アプリ UI (.NET MAUI) アプリをコンパイルすると、コンパイラによってアプリ コードが Microsoft Intermediate Language (MSIL) に変換されます。 シミュレーターまたは Mac Catalyst アプリで iOS アプリを実行すると、.NET 共通言語ランタイム (CLR) は Just-In-Time (JIT) コンパイラを使用して MSIL をコンパイルします。 実行時に MSIL はネイティブ コードにコンパイルされ、アプリの適切なアーキテクチャで実行できます。

ただし、Apple によって設定された iOS にはセキュリティ制限があり、デバイス上で動的に生成されたコードの実行を禁止します。 同様に、動的に生成されたコードの実行は、シミュレーターの ARM64 アーキテクチャで実行されている iOS アプリと、ARM64 アーキテクチャで実行されている Mac Catalyst アプリでは実行できません。 この制限を満たすために、iOS および Mac Catalyst アプリは、Ahead Of Time (AOT) コンパイラを使用してマネージド コードをコンパイルします。 これにより、Apple デバイスまたはネイティブ Mac Catalyst バイナリにデプロイできるネイティブ iOS バイナリが生成されます。

AOT は、起動時間の短縮やその他のさまざまなパフォーマンス最適化によって利点を提供します。 ただし、特定の機能がアプリで使用されることも制限されます。

  • ジェネリックのサポートは限られています。 コンパイル時にすべての可能なジェネリック インスタンス化を決定できるわけではありません。 .NET MAUI リリース ビルドで発生する iOS 固有の問題の多くは、この制限が原因です。
  • 動的なコード生成は許可されません。 これは、System.Relection.Emit が使用できないこと、System.Runtime.Remoting がサポートされていないこと、C# 動的型の一部の使用が許可されていないことを意味します。

AOT 制限が発生すると、「AOT 専用モードで実行中に JIT コンパイル メソッドを試みる」というメッセージとともに System.ExecutionEngineException がスローされます。

Mono インタープリターは、プラットフォームの制限に従いながら、これらの制限を克服します。 これにより、アプリの一部を実行時に解釈しながら、AOT で残りの部分をコンパイルできます。 ただし、運用アプリでインタープリターを使用する場合には、いくつかの潜在的な欠点があります。

  • 通常、インタープリターが有効になっているとアプリのサイズは大幅に縮小されますが、場合によってはアプリのサイズが大きくなる場合があります。
  • 解釈されたコードは AOT コンパイル コードよりも実行速度が遅いため、アプリの実行速度が遅くなります。 この実行速度の低下は、測定不可能から許容できないまで多岐にまたがるので、パフォーマンス テストを実行する必要があります。
  • クラッシュ レポートのネイティブ スタック トレースには、実行中のコードをメンションしないインタープリターの汎用フレームが含まれているため、あまり役に立ちません。 ただし、マネージド スタック トレースは変更されません。

インタープリターは、.NET MAUI デバッグ ビルドに対して既定で有効になっており、リリース ビルドに対して有効にすることができます。

ヒント

.NET MAUI iOS アプリまたは ARM64 ベースの Mac Catalyst アプリがデバッグ ビルドとして正しく動作するにもかかわらず、リリース ビルドとしてクラッシュする場合は、アプリのリリース ビルドでインタープリターを有効にしてみてください。 アプリまたはそのライブラリの 1 つが、インタープリターを必要とする機能を使用している可能性があります。

インタープリターを有効にする

iOS リリース ビルドで Mono インタープリターを有効にするには、$(UseInterpreter) MSBuild プロパティを .NET MAUI アプリのプロジェクト ファイルの 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 を指定してすべてのアセンブリを解釈するか、-all を指定してすべてを AOT コンパイルします。
  • MyAssembly を指定して個々のアセンブリを解釈するか、-MyAssembly を指定して個々のアセンブリを AOT コンパイルします。
  • 組み合わせて一部のアセンブリを解釈し、他のアセンブリを AOT コンパイルします。

警告

インタープリターはネイティブ AOT デプロイと互換性がないため、 $(UseInterpreter) ネイティブ AOT を使用する場合、MSBuild プロパティと $(MtouchInterpreter) MSBuild プロパティは無効になります。 詳細については、ネイティブ 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 を除くすべてのアセンブリを AOT コンパイルする方法を示しています。

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

重要

インタープリターによって実行されるスタック フレームは、有用な情報を提供しません。 ただし、インタープリターはアセンブリごとに無効にできるため、クラッシュ レポートで一部のアセンブリのスタック フレームを正確に示すことができます。

または、次の例を使用して、インタープリターが動的なコード生成を実行できるようにしながら、すべてのアセンブリを AOT コンパイルします。

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

インタープリターが必要な場合があるもう 1 つの一般的なシナリオは、ARM64 アーキテクチャで実行されている .NET MAUI Mac Catalyst アプリであり、起動時に例外をスローする可能性があります。 この起動例外は、多くの場合、インタープリターを有効にすることで修正できます。

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