Установка приложения занимает минуты с предупреждениями dex2oat - PullRequest
4 голосов
/ 20 сентября 2019

Через некоторое время я заново открыл проект Android Studio, и я вижу быстрые сборки как обычно, но теперь шаг «Установка» из Android Studio (3.5) занимает минуты, а раньше занимал секунды.

Если я открою устройство Logcat во время установки, я смогу увидеть их огромное количество:

W/dex2oat: Method processed more than once: void com.package.base.view.BaseDialog.onSaveInstanceState(android.os.Bundle)
W/dex2oat: Method processed more than once: void com.package.base.view.BaseDialog.onViewCreated(android.view.View, android.os.Bundle)
W/dex2oat: Method processed more than once: void com.package.base.view.BaseDialog.onViewModelCreated()
W/dex2oat: Method processed more than once: void com.package.base.view.BaseDialog.removeCancelListener(com.package.base.view.BaseDialog$CancelListener)
W/dex2oat: Method processed more than once: void com.package.base.view.BaseDialog.removeDismissListener(com.package.base.view.BaseDialog$DismissListener)
W/dex2oat: Method processed more than once: void com.package.base.view.BaseDialog.setChildFragmentInjector(dagger.android.DispatchingAndroidInjector)
W/dex2oat: Method processed more than once: void com.package.base.view.BaseDialog.setSharedValue(java.lang.String, java.lang.Object)
W/dex2oat: Method processed more than once: void com.package.base.view.BaseDialog.setViewModelFactory(androidx.lifecycle.ViewModelProvider$Factory)
W/dex2oat: Method processed more than once: dagger.android.AndroidInjector com.package.base.view.BaseDialog.supportFragmentInjector()
I/dex2oat: Explicit concurrent copying GC freed 647(112KB) AllocSpace objects, 0(0B) LOS objects, 32% free, 12MB/18MB, paused 60us total 250.774ms
I/dex2oat: Explicit concurrent copying GC freed 446(29KB) AllocSpace objects, 0(0B) LOS objects, 32% free, 12MB/18MB, paused 60us total 252.704ms
I/dex2oat: Explicit concurrent copying GC freed 396(13KB) AllocSpace objects, 0(0B) LOS objects, 32% free, 12MB/18MB, paused 67us total 257.367ms
I/dex2oat: Explicit concurrent copying GC freed 413(13KB) AllocSpace objects, 0(0B) LOS objects, 32% free, 12MB/18MB, paused 68us total 258.540ms
I/dex2oat: Explicit concurrent copying GC freed 413(13KB) AllocSpace objects, 0(0B) LOS objects, 32% free, 12MB/18MB, paused 64us total 253.988ms
I/dex2oat: Explicit concurrent copying GC freed 413(13KB) AllocSpace objects, 0(0B) LOS objects, 32% free, 12MB/18MB, paused 61us total 258.701ms
I/dex2oat: Explicit concurrent copying GC freed 413(13KB) AllocSpace objects, 0(0B) LOS objects, 32% free, 12MB/18MB, paused 60us total 255.313ms
I/dex2oat: Explicit concurrent copying GC freed 419(45KB) AllocSpace objects, 0(0B) LOS objects, 32% free, 12MB/18MB, paused 60us total 261.034ms
W/dex2oat: Method processed more than once: void com.package.base.view.BaseFragment.<init>()
W/dex2oat: Method processed more than once: void com.package.base.view.BaseFragment.applyStatusBar(com.package.base.view.BaseFragment$StatusBar)
W/dex2oat: Method processed more than once: void com.package.base.view.BaseFragment.dispatchOnStatusBar()
W/dex2oat: Method processed more than once: void com.package.base.view.BaseFragment.restoreStatusBar(android.app.Activity)
W/dex2oat: Method processed more than once: void com.package.base.view.BaseFragment.saveStatusBar(android.app.Activity)

Кажется, что все методы обрабатываются дважды (по крайней мере), и сборщик мусора кажетсяделать большую работу.

Я не знаю, что случилось, но я бы хотел, чтобы это было так быстро, как сейчас - сейчас развитие невозможно.Кто-нибудь может помочь?

Дополнительная информация

Прежде чем dex2oat запустит этот очень долгий процесс, я вижу следующие журналы:

W/dex2oat: Unexpected CPU variant for X86 using defaults: x86
W/dex2oat: Mismatch between dex2oat instruction set features (ISA: X86 Feature string: -ssse3,-sse4.1,-sse4.2,-avx,-avx2,-popcnt) and those of dex2oat executable (ISA: X86 Feature string: ssse3,-sse4.1,-sse4.2,-avx,-avx2,-popcnt) for the command line:
W/dex2oat: /system/bin/dex2oat --zip-fd=8 --zip-location=base.apk --input-vdex-fd=-1 --output-vdex-fd=10 --oat-fd=9 --oat-location=/data/app/com.package-7KbZxh8JQyXUOcSGvv-5hA==/oat/x86/base.odex --instruction-set=x86 --instruction-set-variant=x86 --instruction-set-features=default --runtime-arg -Xms64m --runtime-arg -Xmx512m --compiler-filter=quicken --swap-fd=11 --debuggable --classpath-dir=/data/app/com.package-7KbZxh8JQyXUOcSGvv-5hA== --class-loader-context=PCL[]
I/dex2oat: /system/bin/dex2oat --input-vdex-fd=-1 --output-vdex-fd=10 --compiler-filter=quicken --debuggable --classpath-dir=/data/app/com.package-7KbZxh8JQyXUOcSGvv-5hA== --class-loader-context=PCL[]
I/dex2oat: Large app, accepted running with swap.

Файл сборки

Это часть build.gradle для модуля приложения.Это многомодульный проект, но остальные файлы очень похожи.

android {

    compileSdkVersion(AndroidBuild.compileSdk)

    defaultConfig {
        applicationId = "com.package"
        minSdkVersion(AndroidBuild.minSdk)
        targetSdkVersion(AndroidBuild.targetSdk)
        versionCode = 7
        versionName = "0.2.0"
        vectorDrawables.useSupportLibrary = true
        renderscriptTargetApi = 24
        renderscriptSupportModeEnabled = true
        multiDexEnabled = true

        testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
        testInstrumentationRunnerArgument("clearPackageData", "true")
    }

    signingConfigs {
        create("release") {
            // signing stuff
        }
    }

    testOptions {
        // execution = "ANDROIDX_TEST_ORCHESTRATOR"
    }

    buildTypes {
        getByName("release") {
            signingConfig = signingConfigs.getByName("release")
            isShrinkResources = true
            isMinifyEnabled = true
            proguardFile(getDefaultProguardFile("proguard-defaults.txt"))
            proguardFile("proguard-rules.pro")
        }
        getByName("debug") {
            versionNameSuffix = "-debug"
            // Hoping that this should speed up builds due to multidexing
            defaultConfig.minSdkVersion(21)
        }
    }

    dataBinding.isEnabled = true
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_1_8
        targetCompatibility = JavaVersion.VERSION_1_8
    }
}

Вывод aapt при использовании vmSafeMode = "true"

Вывод при запуске ./Library/Android/sdk/build-tools/29.0.2/aapt list -a app-debug.apk огромен, вставляеттолько соответствующая часть:

E: application (line=57)
  A: android:theme(0x01010000)=@0x7f11014c
  A: android:label(0x01010001)=@0x7f100002
  A: android:icon(0x01010002)=@0x7f0e0001
  A: android:name(0x01010003)="com.package.App" (Raw: "com.package.App")
  A: android:debuggable(0x0101000f)=(type 0x12)0xffffffff
  A: android:allowBackup(0x01010280)=(type 0x12)0xffffffff
  A: android:vmSafeMode(0x010102b8)=(type 0x12)0xffffffff
  A: android:supportsRtl(0x010103af)=(type 0x12)0xffffffff
  A: android:appComponentFactory(0x0101057a)="androidx.core.app.CoreComponentFactory" (Raw: "androidx.core.app.CoreComponentFactory")

Ответы [ 5 ]

1 голос
/ 27 сентября 2019

Intro

На устройстве сборка кеша в время установки (с использованием dex2oat ), т.е. после приложение было создано на вашей сборочной машине:

предупреждения dex2oat

Это то, откуда приходят предупреждения W/dex2oat: Method processed more than once: на андроиде .googlesource в файле verification_results.cc метод WriterMutexLock mu().

  WriterMutexLock mu(Thread::Current(), verified_methods_lock_);
  auto it = verified_methods_.find(ref);
  if (it != verified_methods_.end()) {
    // TODO: Investigate why are we doing the work again for this method and try to avoid it.
    LOG(WARNING) << "Method processed more than once: " << ref.PrettyMethod();
    if (!Runtime::Current()->UseJitCompilation()) {
      DCHECK_EQ(it->second->GetDevirtMap().size(), verified_method->GetDevirtMap().size());
      DCHECK_EQ(it->second->GetSafeCastSet().size(), verified_method->GetSafeCastSet().size());
    }
    // Delete the new verified method since there was already an existing one registered. It
    // is unsafe to replace the existing one since the JIT may be using it to generate a
    // native GC map.
    delete verified_method;
    return;
  }

The:

// TODO: Investigate why are we doing the work again for this method and try to avoid it.

интересно, кажется, Google знает об этом, несколько.

Это информационное сообщение также интересно:

I / dex2oat: большое приложение, разрешено работать с swap.

Это предлагает , dex2oat обнаружил большое приложение и собирается поменяться ( swapping ОЧЕНЬ медленный, ОЗУ скопирована в хранилище и обратноснова).

Исправления

(1) Уменьшите размер приложения

Уменьшите ваше приложение!См. Уменьшение размера вашего приложения .

(2) Отключение ART

ref1 Создание нового минимального …/app/src/debug/AndroidManifest.xml файл:

<manifest
 xmlns:android="http://schemas.android.com/apk/res/android"> 
 <application android:vmSafeMode="true" />
</manifest>

ref2 android: vmSafeMode

Указывает, будет ли приложение использовать виртуальную машину(ВМ) для работы в безопасном режиме.Значением по умолчанию является «false».

Этот атрибут был добавлен на уровне API 8, где значение «true» отключило компилятор JIT) Dalvik.

Этот атрибутбыл адаптирован на уровне API 22 * ​​1083 *, где значение "true" отключило компилятор ART с опережением времени (AOT).Если для vmSafeMode установлено значение true, этот процесс будет выполняться со следующим аргументом:

(3) Поздняя ручная вставка аргумента с помощью adb shell :

/system/bin/dex2oat ... --compiler-filter=interpret-only

Ваша работа:

 /system/bin/dex2oat --zip-fd=8 --zip-location=base.apk --input-vdex-fd=-1 --output-vdex-fd=10 --oat-fd=9 --oat-location=/data/app/com.package-7KbZxh8JQyXUOcSGvv-5hA==/oat/x86/base.odex --instruction-set=x86 --instruction-set-variant=x86 --instruction-set-features=default --runtime-arg -Xms64m --runtime-arg -Xmx512m --compiler-filter=quicken --swap-fd=11 --debuggable --classpath-dir=/data/app/com.package-7KbZxh8JQyXUOcSGvv-5hA== --class-loader-context=PCL[]

и:

 /system/bin/dex2oat --input-vdex-fd=-1 --output-vdex-fd=10 --compiler-filter=quicken --debuggable --classpath-dir=/data/app/com.package-7KbZxh8JQyXUOcSGvv-5hA== --class-loader-context=PCL[]

(4) Удаление задач

Попробуйте увеличить доступную оперативную память во время установки, закрывненужные приложения (или используйте что-то вроде Greenify ).

(5) Попробуйте использовать Мгновенный запуск

  • Сборка и развертывание только инкрементногоизменения
  • Не переустанавливать приложение.
  • Не перезапускать приложение.
  • Даже не перезапускать действие.

Отладка

Другой метод определения, установлен ли vmSafeMode для данного APK, заключается в использовании инструмента aapt.exe.Вы найдете aapt tool в папке build-tools Android SDK, которая отличается в зависимости от выбранной вами ОС.Вероятно, у вас будет установлено несколько разных версий, и вы найдете его в таком месте, как:

.../Android/sdk/build-tools/22.0.1/aapt.exe

Выполните команду списка:

aapt list -a myapkfile.apk

Это должно привести к выводу, в том числе:

Android manifest:
N: android=http://schemas.android.com/apk/res/android
  E: manifest (line=17)
    A: android:versionCode(0x0101021b)=(type 0x10)0x1
    A: android:versionName(0x0101021c)="1.0" (Raw: "1.0")
    A: package="com.testing.sample.myapp" (Raw: "com.testing.sample.myapp")
    A: platformBuildVersionCode=(type 0x10)0x16 (Raw: "22")         <---NOTE
    A: platformBuildVersionName="5.1.1-1819727" (Raw: "5.1.1-1819727")
    E: uses-sdk (line=22)
      A: android:minSdkVersion(0x0101020c)=(type 0x10)0x15
      A: android:targetSdkVersion(0x01010270)=(type 0x10)0x16
    E: application (line=26)
      A: android:label(0x01010001)=@0x7f0b0001
      A: android:icon(0x01010002)=@0x7f030000
      A: android:debuggable(0x0101000f)=(type 0x12)0xffffffff
      A: android:vmSafeMode(0x010102b8)=(type 0x12)0xffffffff
                       ^
                       |
----------NOTE---------+
1 голос
/ 26 сентября 2019

Прежде всего, что является dex2oat, это работает для Verifying app behavior on the Android runtime (ART), для этого обратитесь по этой ссылке

https://developer.android.com/guide/practices/verifying-apps-art

Теперь, когда вынеобходимо сделать этот процесс более быстрым для сборок

. Вы можете отключить эту ART (заранее) , чтобы оптимизировать отладочное развертывание и ускорить сборку.

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
   ...>

 <application
 ...
 android:vmSafeMode="true">
 ...

Примечание: это возможно только для targetSdkVersion из 22+, и вы запускаете устройство с использованием среды выполнения ART.

после отключения этого будетЧтобы уменьшить время сборки, вы можете обратиться по следующей ссылке https://androidbycode.wordpress.com/2015/07/03/disable-android-art-ahead-of-time-compilation-to-optimize-debug-deployment/

0 голосов
/ 29 сентября 2019

Прежде всего , давайте взглянем на важные концепции, затем сосредоточимся на проблеме и предоставляемых решениях. Я попытался собрать важные и низкоуровневые документы, чтобы найти и объяснить вашу проблему.

Как показывает Logcat, есть много предупреждений о dex2oat tool. Имейте в виду, что dex2oat не является компилятором, это инструмент, который используется ART.И также ART не является компилятором, это комбинация нескольких компиляторов.

ART использует опережающую (AOT) компиляцию, и начиная с Android 7.0 (Nougat или N), он использует гибридную комбинацию AOT, JIT-компиляции и Profile-управляемая компиляция.

Как упоминалось выше, она была запущена в Android 7.0

Давайте углубимся в подробности

Во время установки, ART компилирует приложения, используя инструмент dex2oat на устройстве

Приведенная выше цитата объясняет на устройстве dex2oat tool.it означает, что на устройстве нет инструмента dex2oat, это не будет аблe, чтобы использовать инструмент dex2oat. Как я уже объяснял, dex2oat - это инструмент ART, который был запущен на Android 7. В результате Первое решение (плохо) - использование устройства, которое не включено в инструмент dex2oat (версия

это еще не конец, поэтому сделайте перерыв и выпейте чашку кофе

Второе , Следующее решение должно погрузиться в ART.посмотрите ниже код, который написан c ++

void VerificationResults::ProcessVerifiedMethod(verifier::MethodVerifier* method_verifier) {
  DCHECK(method_verifier != nullptr);
  MethodReference ref = method_verifier->GetMethodReference();
  bool compile = IsCandidateForCompilation(ref, method_verifier->GetAccessFlags());
  const VerifiedMethod* verified_method = VerifiedMethod::Create(method_verifier, compile);
  if (verified_method == nullptr) {
    // We'll punt this later.
    return;
  }
  WriterMutexLock mu(Thread::Current(), verified_methods_lock_);
  auto it = verified_methods_.find(ref);
  if (it != verified_methods_.end()) {
    // TODO: Investigate why are we doing the work again for this method and try to avoid it.
    LOG(WARNING) << "Method processed more than once: " << ref.PrettyMethod();
    if (!Runtime::Current()->UseJitCompilation()) {
      DCHECK_EQ(it->second->GetDevirtMap().size(), verified_method->GetDevirtMap().size());
      DCHECK_EQ(it->second->GetSafeCastSet().size(), verified_method->GetSafeCastSet().size());
    }
    // Delete the new verified method since there was already an existing one registered. It
    // is unsafe to replace the existing one since the JIT may be using it to generate a
    // native GC map.
    delete verified_method;
    return;
  }
  verified_methods_.Put(ref, verified_method);
  DCHECK(verified_methods_.find(ref) != verified_methods_.end());
}

Этот метод создает профилированную компиляцию (я объяснил сначала), который используется ART, и его цель

При следующем перезапуске приложения будет использоваться код, управляемый профилем, и избегать JIT-компиляции во время выполнения для уже скомпилированных методов.Методы, которые JIT-компилируются во время новых запусков, будут добавлены в профиль, который затем будет выбран демоном компиляции

, кратко : избегайте выполнения JIT-компиляции ввремя выполнения для ускорения компиляции во время выполнения.

Ваша точная проблема здесь, каждый раз, когда вы нажимаете кнопку отладки сборки, этот метод вызывается и появляются предупреждения. Вы можете спросить, почему эти предупреждения происходят, икак это исправить?

Как вы упомянули, у вас есть многомодульный проект, и у каждого модуля есть свой файл build.gradle.

Когда вызывается ART (отладка сборки), он пытается собратьмультимодульный проект профильная компиляция во время установки. Поэтому ниже приведена схема.

app.gradle
    dependencies 
       a <= verified 
       b <= verified 
       c <= verified 
module.gradle 
    dependencies 
       a <= ops ! Method processed more than once
       b <= ops ! Method processed more than once
       d <= verified
module2.gradle
    dependencies 
       a <= ops ! Method processed more than once
       x <= verified
       v <= verified

Наконец , мы нашли, в чем наша проблема.мы должны перепроектировать наши файлы Gradle.

Заключение , Эта проблема возникает примерно на 98% из плохо организованных файлов Gradle, либо app.gradle, либо модуля Gradle. Чтобы избежать этих предупреждений, вам следуетиметь глобальные файлы Gradle вместо нескольких независимых файлов Gradle.

Ссылки

Android Runtime (ART) и Dalvik

Формат исполняемого файла Dalvik

Настройка ART

0 голосов
/ 28 сентября 2019

Ниже настройки могут сделать вещи быстрее (у меня есть 8Go RAM, адаптироваться к вашему):

In .. \ android-studio \ bin \ studio64.exe.vmoptions

-Xms2G
-Xmx4G
-XX:ReservedCodeCacheSize=580m
-XX:MetaspaceSize=512m

В studio.exe.vmoptions

-server
-Xms1G
-Xmx2G
-XX:ReservedCodeCacheSize=480m
0 голосов
/ 26 сентября 2019

У меня есть кое-что, что может помочь вам, если вы используете Windows, откройте окно терминала в Android Studio и наберите

gradlew installDebug

или в linux введите

./gradlew installDebug 

для получения дополнительной информации ссылказдесь

https://developer.android.com/studio/build/building-cmdline

...