App-Verhalten in der Android-Laufzeit (ART) überprüfen

Die Android-Laufzeit (ART) ist die Standardlaufzeit für Geräte mit Android. 5.0 (API-Level 21) und höher. Diese Laufzeit bietet eine Reihe von Funktionen die die Leistung und reibungslose Abläufe der Android-Plattform und -Apps verbessern. Weitere Informationen zu den neuen Funktionen von ART finden Sie unter Einführung ART

Einige Techniken, die auf Dalvik funktionieren, funktionieren jedoch nicht bei ART. Dieses Dokument enthält Informationen darüber, worauf Sie beim Migrieren eines vorhandenen App mit ART kompatibel sein. Die meisten Apps sollten funktionieren, wenn sie mit KUNST.

Probleme mit der automatischen Speicherbereinigung beheben

Unter Dalvik finden Apps häufig nützlich, System.gc(), um die automatische Speicherbereinigung aufzurufen. Dies sollte weitaus weniger notwendig mit ART, insbesondere wenn Sie die automatische Speicherbereinigung aufrufen. um den Typ GC_FOR_ALLOC zu verhindern oder Fragmentierung reduzieren. Sie können prüfen, welche Laufzeit verwendet wird, indem du System.getProperty("java.vm.version") anrufst. Wenn ART verwendet wird, wird der Wert der Eigenschaft ist "2.0.0" oder höher.

ART verwendet den Collector Concurrent Copy (CC), der gleichzeitig den Java-Heap verdichtet. Daher sollten Sie es vermeiden, die nicht mit der GC-Komprimierung kompatibel sind, z. B. das Speichern von Verweisen auf das Objekt Instanzdaten). Dies ist besonders wichtig für Apps, bei denen das Java Native Interface (JNI). Weitere Informationen finden Sie unter JNI-Probleme verhindern.

JNI-Probleme vermeiden

Die JNI von ART ist etwas strenger als die von Dalvik. Besonders gut ist es, den CheckJNI-Modus verwenden, um häufige Probleme zu erkennen. Wenn Ihre App C/C++ nutzt erhalten Sie im folgenden Artikel:

Fehlerbehebung Android JNI mit CheckJNI

JNI-Code auf Probleme bei der automatischen Speicherbereinigung prüfen

Der Collector für gleichzeitige Kopiervorgänge kann zur Verdichtung Objekte in den Arbeitsspeicher verschieben. Wenn Sie C/C++ Code verwenden, Vorgänge ausführen, die mit der Verdichtung von GC nicht kompatibel sind. Wir haben die CheckJNI ein, um potenzielle Probleme zu identifizieren (wie in JNI beschrieben) Änderungen bei lokalen Referenzen in ICS

Achten Sie insbesondere auf die Verwendung von Get...ArrayElements() und Release...ArrayElements() Funktionen. In Laufzeiten mit nicht verdichtender Speicherbereinigung (GC) Get...ArrayElements()-Funktionen geben normalerweise einen Verweis auf die tatsächlichen Arbeitsspeicher, der das Array-Objekt stützt. Wenn Sie eine Änderung an einer der Array-Elemente zurückgegeben hat, wird das Array-Objekt selbst geändert (und die Argumente bis Release...ArrayElements() werden normalerweise ignoriert. Wenn jedoch GC verdichtet wird, können die Get...ArrayElements()-Funktionen um eine Kopie der Erinnerung zurückzugeben. Wenn du die Referenz bei der Verdichtung von GC missbrauchst, verwendet wird, kann dies zu Speicherbeschädigungen oder anderen Problemen führen. Beispiel:

  • Wenn Sie Änderungen an den zurückgegebenen Array-Elementen vornehmen, müssen Sie die Methode Release...ArrayElements()-Funktion hinzu, sobald Sie fertig sind, damit die vorgenommenen Änderungen korrekt in die zugrunde liegende Array-Objekt enthält.
  • Wenn Sie die Elemente des Speicherarrays freigeben, müssen Sie die entsprechenden je nachdem, welche Änderungen Sie vorgenommen haben: <ph type="x-smartling-placeholder">
      </ph>
    • Wenn Sie keine Änderungen an den Array-Elementen vorgenommen haben, verwenden Sie Der JNI_ABORT-Modus, der den Arbeitsspeicher freigibt, ohne zu kopieren in das zugrunde liegende Array-Objekt zurück.
    • Wenn Sie Änderungen am Array vorgenommen haben und keinen Verweis benötigen Verwenden Sie außerdem den Code 0. Dieser aktualisiert das Array-Objekt und gibt die Kopie der Erinnerung).
    • Wenn Sie Änderungen am Array vorgenommen haben, für das Sie einen Commit durchführen möchten, Um die Kopie des Arrays zu behalten, verwenden Sie JNI_COMMIT, wodurch das zugrunde liegende Array-Objekt und behält die Kopie bei).
  • Wenn Sie Release...ArrayElements() aufrufen, geben Sie Folgendes zurück: Zeiger, der ursprünglich von Get...ArrayElements() zurückgegeben wurde. Für ist es nicht sicher, den ursprünglichen Zeiger zu erhöhen, zurückgegebene Array-Elemente), übergeben Sie dann den erhöhten Zeiger an Release...ArrayElements() Wird dieser geänderte Zeiger übergeben, falschen Arbeitsspeicher freigegeben werden, was zu Speicherbeschädigungen führt.

Fehlerbehandlung

Die JNI von ART gibt in einigen Fällen Fehler aus, in denen Dalvik dies nicht tut. (Einmal Auch hier können Sie viele solcher Fälle durch Tests mit CheckJNI erkennen.)

Wenn beispielsweise RegisterNatives mit einer Methode aufgerufen wird, nicht existiert (möglicherweise weil die Methode von einem Tool wie ProGuard), wirft ART jetzt NoSuchMethodError ordnungsgemäß aus:

08-12 17:09:41.082 13823 13823 E AndroidRuntime: FATAL EXCEPTION: main
08-12 17:09:41.082 13823 13823 E AndroidRuntime: java.lang.NoSuchMethodError:
    no static or non-static method
    "Lcom/foo/Bar;.native_frob(Ljava/lang/String;)I"
08-12 17:09:41.082 13823 13823 E AndroidRuntime:
    at java.lang.Runtime.nativeLoad(Native Method)
08-12 17:09:41.082 13823 13823 E AndroidRuntime:
    at java.lang.Runtime.doLoad(Runtime.java:421)
08-12 17:09:41.082 13823 13823 E AndroidRuntime:
    at java.lang.Runtime.loadLibrary(Runtime.java:362)
08-12 17:09:41.082 13823 13823 E AndroidRuntime:
    at java.lang.System.loadLibrary(System.java:526)

ART protokolliert auch einen Fehler (sichtbar in Logcat), wenn RegisterNatives ohne Methoden aufgerufen:

W/art     ( 1234): JNI RegisterNativeMethods: attempt to register 0 native
methods for <classname>

Darüber hinaus können die JNI-Funktionen GetFieldID() und GetStaticFieldID() wirft NoSuchFieldError jetzt korrekt anstatt einfach null zurückzugeben. Entsprechend werden GetMethodID() und GetStaticMethodID() wirft NoSuchMethodError jetzt korrekt. Dies kann aufgrund der unbehandelten Ausnahmen oder der die an Java-Aufrufer von nativem Code ausgegeben werden. So können Sie besonders wichtig, um ART-kompatible Apps mit dem CheckJNI-Modus zu testen.

ART erwartet Nutzer der JNI CallNonvirtual...Method()-Methoden (z. B. CallNonvirtualVoidMethod()), um die Deklaration der Methode zu verwenden keine abgeleitete Klasse, wie von der JNI-Spezifikation gefordert.

Probleme mit der Stackgröße vermeiden

Dalvik hatte separate Stacks für nativen Code und Java-Code, mit einem Standard-Java- Stackgröße von 32 KB und eine standardmäßige native Stackgröße von 1 MB. ART hat eine einheitliche für eine bessere Lokalität. Normalerweise ist der ART-Thread-Stapel sollte ungefähr der Größe von Dalvik entsprechen. Wenn Sie jedoch ausdrücklich Stackgrößen festlegen, müssen Sie diese Werte für Apps, die in KUNST.

  • Prüfen Sie in Java die Aufrufe des Thread-Konstruktors, die einen expliziten Stack angeben. Größe. Sie müssen die Größe beispielsweise erhöhen, wenn StackOverflowError auftritt.
  • Prüfen Sie die Verwendung von pthread_attr_setstack() und pthread_attr_setstacksize() für Threads, die auch Java-Code ausführen über JNI. Hier ist ein Beispiel für einen protokollierten Fehler, wenn eine Anwendung versucht, JNI aufzurufen AttachCurrentThread(), wenn die pthread-Größe zu klein ist:
    F/art: art/runtime/thread.cc:435]
        Attempt to attach a thread with a too-small stack (16384 bytes)

Änderungen am Objektmodell

Dalvik erlaubte fälschlicherweise Unterklassen, private Paketmethoden zu überschreiben. ART gibt in folgenden Fällen eine Warnung aus:

Before Android 4.1, method void com.foo.Bar.quux()
would have incorrectly overridden the package-private method in
com.quux.Quux

Wenn Sie die Methode einer Klasse in einem anderen Paket überschreiben möchten, deklarieren Sie die Methode als public oder protected.

Object hat jetzt private Felder. Apps, die Felder reflektieren in ihren Klassenhierarchien nicht versuchen, Felder von Object. Wenn Sie z. B. eine Klasse iterieren, Hierarchie als Teil eines Serialisierungsframeworks

Class.getSuperclass() == java.lang.Object.class

anstatt fortzufahren, bis die Methode null zurückgibt.

Proxy InvocationHandler.invoke() empfängt jetzt null, wenn keine anstelle eines leeren Arrays. Dieses Verhalten wurde bereits dokumentiert, in Dalvik nicht richtig gehandhabt wird. In früheren Versionen von Mockito gibt es Verwenden Sie also beim Testen mit ART eine aktualisierte Mockito-Version.

Probleme bei der AOT-Kompilierung beheben

Die AOT-Java-Kompilierung von ART von ART sollte für alle Standard-Java funktionieren Code. Die Zusammenstellung erfolgt von ARTs dex2oat-Tool; falls Probleme im Zusammenhang mit dex2oat bei der Installation an, damit wir sie schnellstmöglich beheben können (siehe Probleme melden). wie möglich. Beachten Sie die folgenden Punkte:

  • ART führt bei der Installation eine strengere Bytecode-Überprüfung als Dalvik durch. Code, der von den Android-Build-Tools erstellt wird, sollte in Ordnung sein. Einige (insbesondere Tools zur Verschleierung) ungültige Dateien, die von Dalvik toleriert, aber von ART abgelehnt wurden. Wir haben und arbeiten mit den Toolanbietern zusammen, um solche Probleme zu finden und zu beheben. In vielen Fällen die neuesten Versionen Ihrer Tools und das Neugenerieren der DEX-Dateien kann dieses Problem beheben. Probleme.
  • Zu den typischen Problemen, die von der ART-Verifizierung gemeldet werden, gehören: <ph type="x-smartling-placeholder">
      </ph>
    • Ungültiger Kontrollablauf
    • unausgeglichen monitorenter/monitorexit
    • Listengröße der Parametertypen mit Länge 0
  • Einige Anwendungen haben Abhängigkeiten von der installierten .odex-Datei Format /system/framework, /data/dalvik-cache oder im optimierten Ausgabeverzeichnis von DexClassLoader. Diese -Dateien sind jetzt ELF-Dateien und keine erweiterte Form von DEX-Dateien. Während ART versucht, dieselben Benennungs- und Sperrregeln wie bei Dalvik. zum Dateiformat; kann das Format ohne vorherige Ankündigung geändert werden.

    Hinweis:Unter Android 8.0 (API-Level 26) und höher, das optimierte Ausgabeverzeichnis für DexClassLoader wurde eingestellt. Weitere Informationen finden Sie in der Dokumentation zum DexClassLoader() -Konstruktor.

Probleme bei der Berichterstellung

Wenn Probleme auftreten, die nicht auf JNI-Probleme mit der App zurückzuführen sind, melden Sie Nutzen Sie den Issue Tracker für das Android Open Source Project unter https://code.google.com/p/android/issues/list. Füge eine "adb bugreport" und einen Link zur App im Google Play Store, falls verfügbar. Hängen Sie andernfalls, falls möglich, ein APK an, das die das Problem zu lösen. Hinweis: Probleme (einschließlich Anhängen) sind öffentlich. sichtbar sind.