使用dex2oat警告安装应用程序需要几分钟
一段时间后,我重新打开了一个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
On device cache build at install time (using dex2oat) i.e. after the app has been built on your build machine:
这是 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: Investigate why are we doing the work again for this method and try to avoid it.
// TODO: Investigate why are we doing the work again for this method and try to avoid it.
很有趣,似乎Google对此有所了解.
is interesting, seems Google know about it, somewhat.
此信息消息也很有趣:
I/dex2oat:大型应用程序,可以通过交换运行.
I/dex2oat: Large app, accepted running with swap.
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
Create a new minimal …/app/src/debug/AndroidManifest.xml
file:
<manifest
xmlns:android="http://schemas.android.com/apk/res/android">
<application android:vmSafeMode="true" />
</manifest>
ref2 android: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[]