安装应用程序需要几分钟的 dex2oat 警告 [英] Installing app takes minutes with dex2oat warnings
问题描述
我在很长一段时间后重新打开了一个 Android Studio 项目,我看到像往常一样快速构建,但现在 Android Studio (3.5) 的安装"步骤需要几分钟,而过去需要几秒钟.
I have re-opened an Android Studio project after quite some time, and I'm seeing fast builds as usual, but now the "Install" step from Android Studio (3.5) is taking minutes, while it used to take seconds.
如果我在安装时打开设备 Logcat,我可以看到大量这些:
If I open the device Logcat while installing, I can see a huge amount of these:
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)
所有方法似乎都被处理了两次(至少),垃圾收集器似乎做了很多工作.
All methods seem to be processed twice (at least) and the garbage collector seems to be doing a lot of work.
我不知道发生了什么,但我很想拥有如此快的速度 - 现在开发是不可能的.有人可以帮忙吗?
I don't know what happened, but I would love to have this fast as it was - right now developing is impossible. Can anyone help?
在 dex2oat 开始这个很长的过程之前,我可以看到以下日志:
Before dex2oat starts this very long process, I can see the following logs:
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
的一部分.这是一个多模块项目,但其他文件非常相似.
Build file
This is part of build.gradle
for the app module. This is a multi-module project, but the other files are very similar.
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
}
}
使用 vmSafeMode="true" 时的 aapt 输出
运行 ./Library/Android/sdk/build-tools/29.0.2/aapt list -a app-debug.apk
时的输出很大,只粘贴相关部分:
aapt output when using vmSafeMode="true"
Output when running ./Library/Android/sdk/build-tools/29.0.2/aapt list -a app-debug.apk
is huge, pasting only the relevant part:
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")
推荐答案
Intro
在设备上 缓存构建在安装时(使用dex2oat) 即之后应用已在您的构建机器上构建:
Intro
On device cache build at install time (using dex2oat) i.e. after the app has been built on your build machine:
这是 W/dex2oat:方法处理多次:
警告来自 android.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;
}
:
//TODO:调查我们为什么要为这个方法再次做这项工作并尽量避免它.
很有趣,似乎谷歌知道,有点.
is interesting, seems Google know about it, somewhat.
这条信息消息也很有趣:
This Info message is also interesting:
I/dex2oat:大型应用程序,接受以交换方式运行.
I/dex2oat: Large app, accepted running with swap.
这表明dex2oat
检测到一个大型应用程序,并且将要交换 (交换 非常慢,RAM 复制到存储,然后再返回.
This suggests the dex2oat
has detected a large app, and is going to swap (swapping is VERY slow, RAM copied to storage, and back again).
精简您的应用程序!请参阅缩小应用大小.
Slim down your app! See Reduce your app size.
ref1创建一个新 最小 .../app/src/debug/AndroidManifest.xml
文件:
<manifest
xmlns:android="http://schemas.android.com/apk/res/android">
<application android:vmSafeMode="true" />
</manifest>
ref2android:vmSafeMode
指示应用程序是否希望虚拟机 (VM)在安全模式下运行.默认值为false".
Indicates whether the app would like the virtual machine (VM) to operate in safe mode. The default value is "false".
此属性是在 API 级别 8 中添加的,其中值为true"禁用 Dalvik 即时 (JIT) 编译器.
This attribute was added in API level 8 where a value of "true" disabled the Dalvik just-in-time (JIT) compiler.
此属性在 API 级别 22 中进行了调整,其中值为true"禁用了 ART 提前 (AOT) 编译器.当 vmSafeMode
是设置为 true
此过程将使用以下内容执行论点:
This attribute was adapted in API level 22 where a value of "true"
disabled the ART ahead-of-time (AOT) compiler. When vmSafeMode
is
set to true
this process will be executed with the following
argument:
(3) 使用 adb shell 后期手动插入参数:
(3) Late manual argument insertion with 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) 移除任务
尝试通过关闭不需要的应用程序(或使用类似 绿色化).
- 仅构建和部署增量更改
- 不要重新安装该应用.
- 不要重启应用.
- 甚至不要重新启动 Activity.
确定是否为给定设置了 vmSafeMode
的另一种方法APK
就是使用aapt.exe
工具.您将在 aapt 工具
中找到Android SDK
的 build-tools
文件夹,不同之处在于位置基于您选择的操作系统.你可能会有几个安装了不同的版本,可以在以下位置找到它:
Another method for determining if
vmSafeMode
is set for a givenAPK
is to use theaapt.exe
tool. You will find theaapt tool
in thebuild-tools
folder of theAndroid SDK
, which differs in location based on your chosen OS. You will probably have several different versions installed and will find it in a location such as:
.../Android/sdk/build-tools/22.0.1/aapt.exe
执行列表命令:
aapt list -a myapkfile.apk
这应该产生的输出包括:
This should produce output including:
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---------+
这篇关于安装应用程序需要几分钟的 dex2oat 警告的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!