ART(Android 런타임)에서 앱 동작 확인

Android 런타임 (ART)은 Android를 실행하는 기기의 기본 런타임입니다. 5.0 (API 수준 21) 이상 이 런타임은 다양한 기능을 Android 플랫폼과 앱의 성능과 부드러움을 개선하기 위한 애플리케이션입니다. ART의 새로운 기능에 대한 자세한 내용은 소개 ART

하지만 Dalvik에서 작동하는 일부 기법이 ART에서는 작동하지 않습니다. 이 기존 Google 계정을 이전할 때 유의할 사항을 알려주는 ART와 호환되어야 합니다. 대부분의 앱은 예술.

가비지 컬렉션(GC) 문제 해결

Dalvik에서는, 앱에서 System.gc(): 가비지 컬렉션 (GC)을 프롬프트합니다. 이 이름은 ART에서는 특히 가비지 컬렉션을 호출하는 경우 훨씬 덜 필요합니다. GC_FOR_ALLOC유형 단편화를 줄일 수 있습니다 사용 중인 런타임을 확인할 수 있습니다. 이를 위해 System.getProperty("java.vm.version")를 호출합니다. ART가 사용 중인 경우 속성의 값 "2.0.0" 이상입니다.

ART는 동시에 Java 힙을 압축하는 동시 복사 (CC) 컬렉터를 사용합니다. 이러한 이유로 인해 간결한 GC와 호환되지 않는 (예: 객체에 포인터 저장) 인스턴스 데이터) 이것은 Java 네이티브 인터페이스 (JNI) 자세한 내용은 JNI 문제 예방을 참고하세요.

JNI 문제 예방

ART의 JNI는 Dalvik의 JNI보다 다소 엄격합니다. 특히 좋은 생각은 CheckJNI 모드를 사용하여 일반적인 문제를 잡아낼 수 있습니다. 앱에서 C/C++를 사용하는 경우 다음 도움말을 검토해야 합니다.

디버깅 CheckJNI를 사용한 Android JNI

가비지 컬렉션 문제를 위해 JNI 코드 확인

동시 복사 (CC) 컬렉터는 압축을 위해 메모리의 객체를 이동할 수 있습니다. C/C++ 코드를 사용하는 경우 간결한 GC와 호환되지 않는 작업을 수행할 수 없습니다. Google은 CheckJNI를 통해 몇 가지 잠재적인 문제를 식별할 수 있습니다 (JNI에 설명됨). ICS의 로컬 참조 변경사항 참조).

특히 주목해야 할 영역은 Get...ArrayElements()Release...ArrayElements() 함수와 비교합니다. 비압축 GC를 사용하는 런타임에서는 Get...ArrayElements() 함수는 일반적으로 실제 메모리를 생성합니다. 기존 규칙 중 하나를 변경하면 배열 요소가 반환되면 배열 객체 자체가 변경됩니다 (그리고 인수는 Release...ArrayElements()에 대한 표현식은 일반적으로 무시됩니다. 그러나 간결한 GC가 사용 중이면 Get...ArrayElements() 함수가 메모리의 사본을 반환합니다 GC를 압축할 때 참조를 오용하는 경우 메모리 손상이나 기타 문제가 발생할 수 있습니다. 예를 들면 다음과 같습니다.

  • 반환된 배열 요소를 변경하는 경우 완료되면 적절한 Release...ArrayElements() 함수를 호출합니다. 변경한 내용이 기본 배열 객체입니다.
  • 메모리 배열 요소를 해제할 때는 적절한 변경 내용에 따라 다음 중 하나를 선택합니다. <ph type="x-smartling-placeholder">
      </ph>
    • 배열 요소를 변경하지 않은 경우 JNI_ABORT 모드 - 복사하지 않고 메모리를 해제합니다. 기본 배열 객체로 다시 변경됩니다.
    • 배열을 변경했고 참조가 필요하지 않은 경우 더 많은 경우 0 코드를 사용합니다. 이 코드는 배열 객체를 업데이트하고 메모리 사본).
    • 커밋하려는 배열을 변경했고 커밋할 배열을 배열의 사본을 유지하려면 JNI_COMMIT( 사본은 보관)
  • Release...ArrayElements()를 호출하면 원래 Get...ArrayElements()에서 반환한 포인터입니다. 대상 예를 들어, 원래 포인터를 증가시키는 것은 반환된 배열 요소)를 통해 증가된 포인터를 Release...ArrayElements() 수정된 포인터를 전달하면 메모리 손상을 야기할 수 있습니다.

오류 처리

ART의 JNI는 Dalvik에서는 발생하지 않는 여러 상황에서 오류를 발생시킵니다. (한 번 CheckJNI로 테스트하면 이러한 경우를 많이 잡아낼 수 있습니다.)

예를 들어 RegisterNatives가 가 존재하지 않는 경우 (예: ProGuard), 이제 ART에서 NoSuchMethodError이 제대로 발생합니다.

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)

RegisterNatives가 다음과 같은 경우 ART는 오류 (logcat에 표시됨)도 로깅합니다. 다음과 같이 메서드 없이 호출됩니다.

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

또한 JNI 함수 GetFieldID() 및 이제 GetStaticFieldID()에서 NoSuchFieldError이 제대로 발생합니다. null을 반환하는 것이 아니라 마찬가지로 GetMethodID() 및 이제 GetStaticMethodID()에서 NoSuchMethodError이 제대로 발생합니다. 이로 인해 처리되지 않은 예외 또는 예외가 발생할 수 있습니다. 이렇게 하면 CheckJNI 모드에서 ART 호환 앱을 테스트하는 데 특히 중요합니다.

ART는 JNI CallNonvirtual...Method() 메서드의 사용자를 예상합니다. (예: CallNonvirtualVoidMethod())를 사용하여 메서드의 선언을 사용합니다. 클래스여야 합니다(JNI 사양에서 요구하는 바에 따라).

스택 크기 문제 예방

Dalvik에는 네이티브 코드와 Java 코드를 위한 별도의 스택이 있었으며, 기본 Java 스택 크기는 32KB이고 기본 네이티브 스택 크기는 1MB입니다. ART는 더 나은 지역성 확보를 위한 스택입니다. 일반적으로 ART Thread 스택 크기는 Dalvik과 거의 같아야 합니다. 그러나 스택 크기를 설정하는 경우 애플리케이션에서 실행 중인 앱에 대해 해당 값을 예술.

  • Java에서 명시적 스택을 지정하는 Thread 생성자 호출을 검토합니다. 있습니다. 예를 들어 StackOverflowError이 발생하면 크기를 늘려야 합니다.
  • C/C++에서 pthread_attr_setstack() 및 다음을 통해 Java 코드도 실행하는 스레드의 경우 pthread_attr_setstacksize() 지원합니다. 다음은 앱이 JNI를 호출하려고 할 때 로깅되는 오류의 예입니다. pthread 크기가 너무 작으면 AttachCurrentThread()를 반환합니다.
    F/art: art/runtime/thread.cc:435]
        Attempt to attach a thread with a too-small stack (16384 bytes)

객체 모델 변경

Dalvik에서는 하위 클래스가 package-private 메서드를 재정의하도록 잘못 허용했습니다. 이런 경우 ART에서는 경고가 발생합니다.

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

다른 패키지에서 클래스의 메서드를 재정의하려면 메서드를 public 또는 protected로 지정합니다.

이제 Object에 비공개 필드가 있습니다. 필드에 반영된 앱 너무 복잡하게 생각하지 않도록 주의해서 Object의 필드입니다. 예를 들어 클래스를 반복하는 경우 계층 구조를 직렬화해야 하며

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

메서드가 null를 반환할 때까지 계속하지 마세요.

이제 프록시 InvocationHandler.invoke()null을 수신합니다. 인수를 사용하세요. 이 동작은 이전에 문서화되었지만 Dalvik에서 올바르게 처리되지 않을 수도 있습니다. 이전 버전의 Mockito는 따라서 ART로 테스트할 때는 업데이트된 Mockito 버전을 사용하세요.

AOT 컴파일 문제 해결

ART의 AOT (Ahead-Of-Time) Java 컴파일은 모든 표준 Java에서 작동해야 합니다. 있습니다. 컴파일은 ART에서 실행됩니다. dex2oat 도구 kubectl 명령어와 관련된 문제가 발생하는 경우 dex2oat인 경우 Google에 알려주시면 (문제 신고 참조) 문제를 최대한 빨리 해결해 드리겠습니다. 할 수 있습니다. 주목할 몇 가지 문제:

  • ART는 설치 시에 Dalvik보다 더 엄격한 바이트코드 검사를 수행합니다. Android 빌드 도구에서 생성된 코드는 괜찮을 것입니다. 그러나 후처리 툴 (특히 난독화를 수행하는 툴)은 Dalvik에서는 허용되지만 ART에서는 거부된 잘못된 파일 우리는 지금까지 도구 공급업체와 협력하여 이러한 문제를 찾아 해결합니다 많은 경우 최신 버전의 도구를 사용하고 DEX 파일을 재생성하면 이러한 문제를 해결할 수 있습니다 문제를 해결하는 데 도움이 됩니다
  • ART 확인자에 의해 플래그되는 몇 가지 일반적인 문제는 다음과 같습니다. <ph type="x-smartling-placeholder">
      </ph>
    • 잘못된 제어 흐름
    • 불균형 monitorenter/monitorexit
    • 길이가 0인 매개변수 형식 목록 크기
  • 일부 앱의 경우 설치된 .odex 파일에 종속 항목이 있습니다. /system/framework, /data/dalvik-cache 또는 DexClassLoader의 최적화된 출력 디렉터리에 저장됩니다. 이러한 파일은 이제 확장된 형식의 DEX 파일이 아니라 ELF 파일입니다. ART가 시도하는 동안 Dalvik과 동일한 명명 및 잠금 규칙을 따르기 위해 앱은 파일 형식 형식은 예고 없이 변경될 수 있습니다.

    참고: Android 8.0 (API 수준 26) 및 DexClassLoader에 최적화된 출력 디렉터리 지원 중단되었습니다. 자세한 내용은 DexClassLoader() 생성자에 전달해야 합니다.

문제 보고하기

앱 JNI 문제 이외의 원인으로 문제가 발생한 경우 https://code.google.com/p/android/issues/list에서 Android 오픈소스 프로젝트 Issue Tracker를 통해 문제를 해결할 수 있습니다. "adb bugreport" 및 Google Play 스토어(제공되는 경우) 또는 가능한 경우 문제를 재현하는 APK를 첨부해 주세요. 있습니다. 참고로 문제 (첨부파일 포함)는 공개적으로 게시되며 표시됩니다.