Condividi tramite


Interprete Mono in iOS e Mac Catalyst

Quando si compila un'app .NET Multi-Platform App UI (.NET MAUI) per iOS o Mac Catalyst, il compilatore trasforma il codice dell'app in Microsoft Intermediate Language (MSIL). Quando si esegue l'app iOS nel simulatore o nell'app Mac Catalyst, .NET Common Language Runtime (CLR) compila MSIL usando un compilatore JIT (Just in Time). In fase di esecuzione il codice MSIL viene compilato in codice nativo, che può essere eseguito nell'architettura corretta per l'app.

Tuttavia, esiste una restrizione di sicurezza per iOS, impostata da Apple, che impedisce l'esecuzione di codice generato dinamicamente in un dispositivo. Analogamente, l'esecuzione di codice generato dinamicamente non è consentita nelle app iOS in esecuzione nell'architettura ARM64 nel simulatore e nelle app Mac Catalyst in esecuzione nell'architettura ARM64. Per soddisfare questa restrizione, le app iOS e Mac Catalyst usano un compilatore AOT (Ahead of Time) per compilare il codice gestito. Questo produce un file binario iOS nativo che può essere distribuito nei dispositivi Apple o un file binario Mac Catalyst nativo.

AOT offre vantaggi grazie a una riduzione del tempo di avvio e a varie altre ottimizzazioni delle prestazioni. Tuttavia, limita anche l'uso di determinate funzionalità nell'app:

  • È disponibile un supporto limitato per i generics. Non tutte le possibili istanze generica possono essere determinate in fase di compilazione. Molti dei problemi specifici di iOS riscontrati nelle build di versione MAUI di .NET sono dovuti a questa limitazione.
  • La generazione dinamica del codice non è consentita. Ciò significa che System.Relection.Emit non è disponibile, non è disponibile alcun supporto per System.Runtime.Remotinge alcuni usi del tipo dinamico C# non sono consentiti.

Quando si verifica una restrizione AOT, verrà generata un'eccezione System.ExecutionEngineException con un messaggio "Tentativo di compilazione JIT durante l'esecuzione in modalità aot-only".

L'interprete Mono supera queste restrizioni rispettando al tempo stesso le restrizioni della piattaforma. Consente di interpretare alcune parti dell'app in fase di esecuzione, mentre AOT compila il resto. Esistono tuttavia alcuni potenziali svantaggi per l'uso dell'interprete in un'app di produzione:

  • Anche se le dimensioni dell'app si riducono in genere in modo significativo quando l'interprete è abilitato, in alcuni casi le dimensioni dell'app possono aumentare.
  • La velocità di esecuzione dell'app sarà più lenta perché il codice interpretato viene eseguito più lentamente rispetto al codice compilato AOT. Questa riduzione della velocità di esecuzione può variare da non verificabile a inaccettabile, quindi è consigliabile eseguire test delle prestazioni.
  • Le analisi dello stack nativo nei report di arresto anomalo diventano meno utili, perché contengono frame generici dall'interprete che non menzionano il codice in esecuzione. Tuttavia, le tracce dello stack gestito non cambieranno.

L'interprete è abilitato per impostazione predefinita per le compilazioni di debug MAUI .NET e può essere abilitato per le build di versione.

Suggerimento

Se l'app .NET MAUI iOS o l'app Mac Catalyst basata su ARM64 funziona correttamente come compilazione di debug, ma si arresta in modo anomalo come build di versione, provare ad abilitare l'interprete per la build di versione dell'app. Potrebbe essere che l'app o una delle relative librerie usi una funzionalità che richiede l'interprete.

Abilitare l'interprete

L'interprete Mono può essere abilitato nelle build di versione iOS impostando la $(UseInterpreter) proprietà MSBuild su true nel file di progetto dell'app MAUI .NET:

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

L'interprete può anche essere abilitato per le build di rilascio di Mac Catalyst su ARM64:

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

Avviso

Non abilitare l'interprete per le build di versione in Android perché disabilita la compilazione JIT.

In iOS e Mac Catalyst, l'interprete può essere abilitato anche con la $(MtouchInterpreter) proprietà MSBuild. Questa proprietà accetta facoltativamente un elenco delimitato da virgole di assembly da interpretare. Inoltre, all può essere usato per specificare tutti gli assembly e, se preceduto da un segno meno, verrà compilato un assembly AOT. Ciò consente di:

  • Interpretare tutti gli assembly specificando all o AOT compilare tutti gli elementi specificando -all.
  • Interpretare i singoli assembly specificando MyAssembly o AOT compilare singoli assembly specificando -MyAssembly.
  • Combinare e trovare la corrispondenza per interpretare alcuni assembly e AOT compila altri assembly.

Avviso

L'interprete non è compatibile con la distribuzione AOT nativa e pertanto le $(UseInterpreter) proprietà e $(MtouchInterpreter) MSBuild non hanno alcun effetto quando si usa Native AOT. Per altre informazioni, vedere Distribuzione AOT nativa.

Nell'esempio seguente viene illustrato come interpretare tutti gli assembly ad eccezione di System.Xml.dll:

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

Nell'esempio seguente viene illustrato come compilare tutti gli assembly AOT ad eccezione di 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>

Importante

Un stack frame eseguito dall'interprete non fornirà informazioni utili. Tuttavia, poiché l'interprete può essere disabilitato per ogni assembly, è possibile che gli stack frame di alcuni assembly vengano rappresentati in modo accurato nei report sugli arresti anomali.

In alternativa, usare l'esempio seguente per compilare tutti gli assembly AOT, consentendo comunque all'interprete di eseguire la generazione dinamica del codice:

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

Un altro scenario comune in cui l'interprete è talvolta necessario è un'app Catalyst Mac MAUI .NET in esecuzione nell'architettura ARM64, che può generare un'eccezione all'avvio. Questa eccezione di avvio può spesso essere risolta abilitando l'interprete:

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