Mono-Interpreter auf iOS und Mac Catalyst
Wenn Sie eine .NET Multi-Platform App UI (.NET MAUI)-App für iOS oder Mac Catalyst kompilieren, wandelt der Compiler Ihren App-Code in Microsoft Intermediate Language (MSIL) um. Wenn Sie die iOS-App im Simulator oder die Mac Catalyst-App ausführen, kompiliert die .NET Common Language Runtime (CLR) die MSIL mit einem Just in Time (JIT)-Compiler. Zur Laufzeit wird die MSIL in systemeigenem Code kompiliert, der auf der richtigen Architektur für Ihre App ausgeführt werden kann.
Es gibt jedoch eine von Apple festgelegte Sicherheitsbeschränkung für iOS, wodurch die Ausführung von dynamisch generiertem Code auf einem Gerät nicht zulässig ist. Ebenso ist die Ausführung von dynamisch generiertem Code in iOS-Apps, die auf der ARM64-Architektur im Simulator ausgeführt werden, und auf Mac Catalyst-Apps, die auf der ARM64-Architektur ausgeführt werden, nicht zulässig. Um diese Einschränkung zu erfüllen, verwenden iOS- und Mac Catalyst-Apps einen AOT-Compiler (Ahead of Time), um den verwalteten Code zu kompilieren. Dies erzeugt eine systemeigene iOS-Binärdatei, die auf Apple-Geräten oder einer nativen Mac Catalyst-Binärdatei bereitgestellt werden kann.
AOT bietet Vorteile durch eine Reduzierung der Startzeit und verschiedene andere Leistungsoptimierungen. Es schränkt jedoch auch bestimmte Features ein, die in Ihrer App verwendet werden:
- Die Unterstützung für Generics ist eingeschränkt. Nicht jede mögliche generische Instanziierung kann zur Kompilierungszeit bestimmt werden. Viele der iOS-spezifischen Probleme in .NET MAUI-Releasebuilds sind auf diese Einschränkung zurückzuführen.
- Dynamische Codegenerierung ist nicht zulässig. Dies bedeutet, dass
System.Relection.Emit
nicht verfügbar ist, es gibt keine Unterstützung fürSystem.Runtime.Remoting
und einige Verwendungen des C# dynamischen Typs sind nicht zulässig.
Wenn eine AOT-Einschränkung auftritt, wird ein System.ExecutionEngineException
mit der Meldung „Versuch der JIT-Kompilierungsmethode während der Ausführung im Modus ’Nur AOT'“ ausgelöst.
Der Mono-Interpreter übergeht diese Einschränkungen, während die Plattformbeschränkungen eingehalten werden. Sie können einige Teile Ihrer App zur Laufzeit interpretieren, während AOT den Rest kompiliert. Es gibt jedoch einige potenzielle Nachteile bei der Verwendung des Interpreters in einer Produktions-App:
- Während sich die Größe der App in der Regel deutlich verringert, wenn der Interpreter aktiviert ist, kann sie in bestimmten Fällen auch größer werden.
- Die Ausführungsgeschwindigkeit der App ist langsamer, da interpretierter Code langsamer ausgeführt wird als der kompilierte AOT-Code. Diese Reduzierung der Ausführungsgeschwindigkeit kann von nicht messbar bis inakzeptabel reichen, sodass Leistungstests durchgeführt werden sollten.
- Systemeigene Stapelüberwachungen in Absturzberichten sind weniger nützlich, da sie generische Frames aus dem Interpreter enthalten, die nicht den Code erwähnen, der gerade ausgeführt wird. Verwaltete Stapelüberwachungen werden sich jedoch nicht ändern.
Der Interpreter ist standardmäßig für .NET MAUI-Debugbuilds aktiviert und kann für Releasebuilds aktiviert werden.
Tipp
Wenn Ihre .NET MAUI iOS-App oder ARM64-basierte Mac Catalyst-App ordnungsgemäß als Debugbuild funktioniert, aber dann als Releasebuild abstürzt, sollten Sie versuchen, den Interpreter für den Releasebuild Ihrer App zu aktivieren. Es kann sein, dass Ihre App oder eine ihrer Bibliotheken ein Feature verwendet, das den Interpreter erfordert.
Aktivieren des Interpreters
Der Mono-Interpreter kann in iOS-Releasebuilds aktiviert werden, indem die $(UseInterpreter)
MSBuild-Eigenschaft in der Projektdatei Ihrer .NET MAUI-App auf true
festgelegt wird:
<PropertyGroup Condition="$(TargetFramework.Contains('-ios')) and '$(Configuration)' == 'Release'">
<UseInterpreter>true</UseInterpreter>
</PropertyGroup>
Der Interpreter kann auch für Mac Catalyst Releasebuilds auf ARM64 aktiviert werden:
<PropertyGroup Condition="'$(RuntimeIdentifier)' == 'maccatalyst-arm64' and '$(Configuration)' == 'Release'">
<UseInterpreter>true</UseInterpreter>
</PropertyGroup>
Warnung
Aktivieren Sie den Interpreter nicht für Releasebuilds auf Android, da die JIT-Kompilierung deaktiviert wird.
Auf iOS und Mac Catalyst kann der Interpreter auch mit der $(MtouchInterpreter)
-MSBuild-Eigenschaft aktiviert werden. Diese Eigenschaft verwendet optional eine durch Trennzeichen getrennte Liste von Assemblys, die interpretiert werden sollten. Darüber hinaus kann all
verwendet werden, um alle Assemblys anzugeben, und wenn ein Minuszeichen vorangestellt wird, wird eine Assembly AOT-kompiliert. Hierdurch wird Folgendes ermöglicht:
- Interpretieren Sie alle Assemblys, indem Sie
all
angeben oder kompilieren Sie alles AOT, indem Sie-all
angeben. - Interpretieren Sie einzelne Assemblys, indem Sie MyAssembly angeben, oder AOT-kompilieren Sie einzelne Assemblys, indem Sie -MyAssembly angeben.
- Mischen und abgleichen, um einige Assemblys zu interpretieren und andere Assemblys AOT zu kompilieren.
Warnung
Der Interpreter ist nicht mit der nativen AOT-Bereitstellung kompatibel, und daher haben die $(UseInterpreter)
$(MtouchInterpreter)
MsBuild-Eigenschaften keine Auswirkungen, wenn Native AOT verwendet wird. Weitere Informationen finden Sie unter Bereitstellung von nativem AOT.
Das folgende Beispiel zeigt, wie alle Assemblys außer System.Xml.dll interpretiert werden:
<PropertyGroup Condition="$(TargetFramework.Contains('-ios')) and '$(Configuration)' == 'Release'">
<!-- Interpret everything, except System.Xml.dll -->
<MtouchInterpreter>all,-System.Xml</MtouchInterpreter>
</PropertyGroup>
Das folgende Beispiel zeigt, wie alle Assemblys außer System.Numerics.dll AOT-kompiliert werden:
<PropertyGroup Condition="$(TargetFramework.Contains('-ios')) and '$(Configuration)' == 'Release'">
<!-- AOT everything, except System.Numerics.dll, which will be interpreted -->
<MtouchInterpreter>-all,System.Numerics</MtouchInterpreter>
</PropertyGroup>
Wichtig
Ein vom Interpreter ausgeführter Stapelrahmen liefert keine nützlichen Informationen. Da der Interpreter jedoch für einzelne Assemblys deaktiviert werden kann, ist es möglich, Stapelrahmen von einigen Assemblys korrekt in Absturzberichten darzustellen.
Verwenden Sie alternativ das folgende Beispiel, um alle Assemblys AOT zu kompilieren, während der Interpreter weiterhin die dynamische Codegenerierung ausführen kann:
<PropertyGroup Condition="$(TargetFramework.Contains('-ios')) and '$(Configuration)' == 'Release'">
<MtouchInterpreter>-all</MtouchInterpreter>
</PropertyGroup>
Ein weiteres gängiges Szenario, bei dem der Interpreter manchmal erforderlich ist, ist eine .NET MAUI Mac Catalyst-App, die auf der ARM64-Architektur ausgeführt wird, was eine Ausnahme beim Start auslösen kann. Diese Startausnahme kann häufig behoben werden, indem der Interpreter aktiviert wird:
<PropertyGroup Condition="'$(RuntimeIdentifier)' == 'maccatalyst-arm64' and '$(Configuration)' == 'Release'">
<MtouchInterpreter>-all,MyAssembly</MtouchInterpreter>
</PropertyGroup>