最近在准备 Boosterv3.0.0 发布前的测试,为了保证 Booster 的质量,对 Android Gradle Plugin3.0.04.1.0 挨个版本进行了适配,并写了大量的集成测试,在跑测试用例的过程中,刚开始跑 debug 的构建测试用例一切挺顺利的,后来脑子一抽,把 release 构建也加上吧,没想到,整个测试用例就卡在 Android Gradle Plugin 3.5.0 的用例上不动了,试了很多次,也一直这样,后来一看,原来已经是 OOM 了,还 dump 了一堆 hprof 文件,看了一下 JUnit 的测试报告才发现,原来是 Metaspace 爆了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
org.gradle.testkit.runner.UnexpectedBuildFailure: Unexpected build execution failure in /var/folders/dy/bxzw01fx3bv9xmsmyy77qgx80000gp/T/junit1018081279555935171 with arguments [assemble, -S, -Pbooster_version=2.4.0, -Pandroid_gradle_version=3.5.0, -Pcompile_sdk_version=28, -Pbuild_tools_version=26.0.3, -Pmin_sdk_version=18, -Ptarget_sdk_version=26]

Output:
> Task :buildSrc:compileJava NO-SOURCE
> Task :buildSrc:compileGroovy NO-SOURCE
> Task :buildSrc:processResources
> Task :buildSrc:classes
> Task :buildSrc:jar
> Task :buildSrc:assemble
> Task :buildSrc:compileTestJava NO-SOURCE
> Task :buildSrc:compileTestGroovy NO-SOURCE
> Task :buildSrc:processTestResources NO-SOURCE
> Task :buildSrc:testClasses UP-TO-DATE
> Task :buildSrc:test NO-SOURCE
> Task :buildSrc:check UP-TO-DATE
> Task :buildSrc:build

> Configure project :
file:/Users/johnsonlee/Workspace/github/didi/booster/booster-android-gradle-v3_5/build/classes/java/main/
file:/Users/johnsonlee/Workspace/github/didi/booster/booster-android-gradle-v3_5/build/classes/kotlin/main/
file:/Users/johnsonlee/Workspace/github/didi/booster/booster-android-gradle-v3_5/build/tmp/kapt3/classes/main/
file:/Users/johnsonlee/Workspace/github/didi/booster/booster-android-gradle-v3_5/build/resources/main
file:/Users/johnsonlee/Workspace/github/didi/booster/booster-android-gradle-compat/build/libs/booster-android-gradle-compat-3.0.0-SNAPSHOT.jar
file:/Users/johnsonlee/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-reflect/1.3.61/2e07c9a84c9e118efb70eede7e579fd663932122/kotlin-reflect-1.3.61.jar
file:/Users/johnsonlee/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib/1.3.61/4702105e97f7396ae41b113fdbdc180ec1eb1e36/kotlin-stdlib-1.3.61.jar
file:/Users/johnsonlee/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-common/1.3.61/65abb71d5afb850b68be03987b08e2c864ca3110/kotlin-stdlib-common-1.3.61.jar
file:/Users/johnsonlee/.gradle/caches/modules-2/files-2.1/org.jetbrains/annotations/13.0/919f0dfe192fb4e063e7dacadee7f8bb9a2672a9/annotations-13.0.jar
file:/Users/johnsonlee/Workspace/github/didi/booster/booster-android-gradle-v3_5/build/classes/kotlin/integrationTest/
WARNING: The specified Android SDK Build Tools version (26.0.3) is ignored, as it is below the minimum supported version (28.0.3) for Android Gradle Plugin 3.5.0.
Android SDK Build Tools 28.0.3 will be used.
To suppress this warning, remove "buildToolsVersion '26.0.3'" from your build.gradle file, as each version of the Android Gradle Plugin now has a default version of the build tools.

> Task :preBuild UP-TO-DATE
> Task :preCnDebugBuild UP-TO-DATE
> Task :compileCnDebugAidl NO-SOURCE
> Task :compileCnDebugRenderscript NO-SOURCE
> Task :checkCnDebugManifest
> Task :generateCnDebugBuildConfig
> Task :mainApkListPersistenceCnDebug
> Task :generateCnDebugResValues
> Task :generateCnDebugResources
> Task :createCnDebugCompatibleScreenManifests
> Task :processCnDebugManifest
> Task :mergeCnDebugShaders
> Task :compileCnDebugShaders
> Task :generateCnDebugAssets
> Task :mergeCnDebugAssets
> Task :processCnDebugJavaRes NO-SOURCE
> Task :checkCnDebugDuplicateClasses
> Task :validateSigningCnDebug
> Task :signingConfigWriterCnDebug
> Task :mergeCnDebugJniLibFolders
> Task :preCnReleaseBuild UP-TO-DATE
> Task :compileCnReleaseAidl NO-SOURCE
> Task :compileCnReleaseRenderscript NO-SOURCE
> Task :checkCnReleaseManifest
> Task :generateCnReleaseBuildConfig
> Task :mainApkListPersistenceCnRelease
> Task :generateCnReleaseResValues
> Task :generateCnReleaseResources
> Task :javaPreCompileCnRelease
> Task :createCnReleaseCompatibleScreenManifests
> Task :processCnReleaseManifest
> Task :prepareLintJar
> Task :mergeCnReleaseShaders
> Task :compileCnReleaseShaders
> Task :generateCnReleaseAssets
> Task :mergeCnReleaseAssets
> Task :processCnReleaseJavaRes NO-SOURCE
> Task :checkCnReleaseDuplicateClasses
> Task :signingConfigWriterCnRelease
> Task :mergeCnReleaseJniLibFolders
> Task :preEnDebugBuild UP-TO-DATE
> Task :compileEnDebugAidl NO-SOURCE
> Task :compileEnDebugRenderscript NO-SOURCE
> Task :checkEnDebugManifest
> Task :generateEnDebugBuildConfig
> Task :mergeCnDebugResources
> Task :processCnDebugResources
> Task :mainApkListPersistenceEnDebug
> Task :generateEnDebugResValues
> Task :generateEnDebugResources
> Task :mergeCnDebugNativeLibs
> Task :stripCnDebugDebugSymbols
> Task :createEnDebugCompatibleScreenManifests
> Task :processEnDebugManifest
> Task :checkEnDebugDuplicateClasses
> Task :mergeEnDebugShaders
> Task :compileEnDebugShaders
> Task :generateEnDebugAssets
> Task :mergeEnDebugAssets
> Task :processEnDebugJavaRes NO-SOURCE
> Task :validateSigningEnDebug
> Task :signingConfigWriterEnDebug
> Task :mergeEnDebugJniLibFolders
> Task :javaPreCompileCnDebug
> Task :compileCnDebugJavaWithJavac
> Task :compileCnDebugSources
> Task :transformClassesWithDexBuilderForCnDebug FAILED
> Task :mergeCnReleaseNativeLibs
> Task :mergeCnDebugJavaResource
> Task :mergeEnDebugNativeLibs
> Task :mergeCnReleaseResources
> Task :javaPreCompileEnDebug
> Task :mergeEnDebugResources
Daemon will be stopped at the end of the build after running out of JVM memory

FAILURE: Build failed with an exception.

* What went wrong:
Metaspace

* Try:
Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Exception is:
java.lang.OutOfMemoryError: Metaspace


* Get more help at https://help.gradle.org

BUILD FAILED in 24s

at org.gradle.testkit.runner.internal.DefaultGradleRunner$2.execute(DefaultGradleRunner.java:255)
at org.gradle.testkit.runner.internal.DefaultGradleRunner$2.execute(DefaultGradleRunner.java:251)
at org.gradle.testkit.runner.internal.DefaultGradleRunner.run(DefaultGradleRunner.java:324)
at org.gradle.testkit.runner.internal.DefaultGradleRunner.build(DefaultGradleRunner.java:251)
at io.bootstage.testkit.gradle.rules.GradleExecutor.finished(GradleExecutor.kt:50)
at org.junit.rules.TestWatcher.finishedQuietly(TestWatcher.java:117)
at org.junit.rules.TestWatcher.access$400(TestWatcher.java:46)
at org.junit.rules.TestWatcher$1.evaluate(TestWatcher.java:64)
at org.junit.rules.TestWatcher$1.evaluate(TestWatcher.java:55)
at org.junit.rules.TestWatcher$1.evaluate(TestWatcher.java:55)
at org.junit.rules.ExternalResource$1.evaluate(ExternalResource.java:48)
at org.junit.rules.RunRules.evaluate(RunRules.java:20)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.runTestClass(JUnitTestClassExecutor.java:110)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:58)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:38)
at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestClassProcessor.processTestClass(AbstractJUnitTestClassProcessor.java:62)
at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:51)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94)
at com.sun.proxy.$Proxy2.processTestClass(Unknown Source)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.processTestClass(TestWorker.java:118)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:182)
at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:164)
at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:412)
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:56)
at java.lang.Thread.run(Thread.java:748)

Gradle 测试

Gradle 插件测试需要引到 Gradle TestKit,每个 @Test 方法前都会动态创建一个 Android Gradle 工程,然后在 @Test 方法后会调用 Gradle Runner 去执行 assemble 这个任务,@Test 方法体中可以操作这个动态生成的 Android Gradle 工程,例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
private const val MIN_SDK_VERSION = 18
private const val TARGET_SDK_VERSION = 30
private val AGP = V30

private val ARGS = arrayOf(
"assemble", "-S",
"-Pbooster_version=${Build.VERSION}",
"-Pandroid_gradle_version=3.0.0",
"-Pcompile_sdk_version=28",
"-Pbuild_tools_version=26.0.3",
"-Pmin_sdk_version=${MIN_SDK_VERSION}",
"-Ptarget_sdk_version=${TARGET_SDK_VERSION}"
)

@Suppress("RemoveCurlyBracesFromTemplate", "FunctionName")
abstract class V30IntegrationTest(val isLib: Boolean) {

private val projectDir = TemporaryFolder()

@get:Rule
val ruleChain: TestRule = rule(projectDir) {
rule(LocalProperties(projectDir::getRoot)) {
rule(TestCaseConfigure(projectDir::getRoot)) {
GradleExecutor(projectDir::getRoot, "4.1", *ARGS)
}
}
}

@Before
fun setup() {
projectDir.copyFromResource("${if (isLib) "lib" else "app"}.gradle", "build.gradle")
projectDir.copyFromResource("buildSrc")
projectDir.copyFromResource("src")
}

@Test
@Case(ScopeFullWithFeaturesTest::class)
fun `test AGPInterface#scopeFullWithFeatures`() {
}

}

class V30AppIntegrationTest : V30IntegrationTest(false)

class V30LibIntegrationTest : V30IntegrationTest(true)

Gradle Runner

Gradle Runner 在执行测试构建任务的时候,会新启一个 GradleDaemon 进程,默认 Gradle Runner 会在 $TMPDIR 目录下创建一个类似于 ~/.gradle 的目录,用来存放缓存文件,刚开始出现 OOM 的时候,以为与 Gradle Runner 有关,后来,重新设置了 Gradle Runner 的目录,OOM 依然存在。

Profiling

OOM 发生在 Metaspace ,大概率跟 class 的加载有关,于是用 VisualVMGradle RunnerGradleDaemon 进程进行分析,发现 Metaspace 的内存涨幅很不可思议,执行到第三个测试用例就 OOM 了:

Metaspace OOM

Test 日志

为了看到更详细的 build 过程,于是,打开了 Test 任务的日志:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
task integrationTest(type: Test) {
description = 'Runs the integration tests.'
group = 'verification'
testClassesDirs = sourceSets.integrationTest.output.classesDirs
classpath = sourceSets.integrationTest.runtimeClasspath
mustRunAfter test
testLogging {
events "passed", "skipped", "failed", "standardOut", "standardError" // 开启日志输出
}
}

task functionalTest(type: Test) {
description = 'Runs the functional tests.'
group = 'verification'
testClassesDirs = sourceSets.functionalTest.output.classesDirs
classpath = sourceSets.functionalTest.runtimeClasspath
mustRunAfter test, integrationTest
testLogging {
events "passed", "skipped", "failed", "standardOut", "standardError" // 开启日志输出
}
}

这样,就可以看到测试工程的 build 的详细过程了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
com.didiglobal.booster.android.gradle.v3_5.V35AppIntegrationTest > test AGPInterface#mergedManifests STANDARD_OUT
> Task :buildSrc:compileJava NO-SOURCE
> Task :buildSrc:compileGroovy NO-SOURCE
> Task :buildSrc:processResources
> Task :buildSrc:classes
> Task :buildSrc:jar
> Task :buildSrc:assemble
> Task :buildSrc:compileTestJava NO-SOURCE
> Task :buildSrc:compileTestGroovy NO-SOURCE
> Task :buildSrc:processTestResources NO-SOURCE
> Task :buildSrc:testClasses UP-TO-DATE
> Task :buildSrc:test NO-SOURCE
> Task :buildSrc:check UP-TO-DATE
> Task :buildSrc:build
> Configure project :
file:/Users/johnsonlee/Workspace/github/didi/booster/booster-android-gradle-v3_5/build/classes/kotlin/integrationTest/
WARNING: The specified Android SDK Build Tools version (26.0.3) is ignored, as it is below the minimum supported version (28.0.3) for Android Gradle Plugin 3.5.0.
Android SDK Build Tools 28.0.3 will be used.
To suppress this warning, remove "buildToolsVersion '26.0.3'" from your build.gradle file, as each version of the Android Gradle Plugin now has a default version of the build tools.

> Task :preBuild UP-TO-DATE
> Task :preCnDebugBuild UP-TO-DATE
> Task :compileCnDebugAidl NO-SOURCE
> Task :compileCnDebugRenderscript NO-SOURCE
> Task :checkCnDebugManifest
> Task :generateCnDebugBuildConfig FROM-CACHE
> Task :javaPreCompileCnDebug FROM-CACHE
> Task :mainApkListPersistenceCnDebug
> Task :generateCnDebugResValues FROM-CACHE
> Task :generateCnDebugResources UP-TO-DATE
> Task :mergeCnDebugResources FROM-CACHE
> Task :createCnDebugCompatibleScreenManifests
> Task :processCnDebugManifest
> Task :processCnDebugResources
> Task :compileCnDebugJavaWithJavac FROM-CACHE
> Task :compileCnDebugSources UP-TO-DATE
> Task :mergeCnDebugShaders FROM-CACHE
> Task :compileCnDebugShaders FROM-CACHE
> Task :generateCnDebugAssets UP-TO-DATE
> Task :mergeCnDebugAssets FROM-CACHE
> Task :processCnDebugJavaRes NO-SOURCE
> Task :mergeCnDebugJavaResource FROM-CACHE
> Task :checkCnDebugDuplicateClasses FROM-CACHE
> Task :transformClassesWithDexBuilderForCnDebug
> Task :mergeExtDexCnDebug FROM-CACHE
> Task :mergeDexCnDebug FROM-CACHE
> Task :validateSigningCnDebug FROM-CACHE
> Task :signingConfigWriterCnDebug FROM-CACHE
> Task :mergeCnDebugJniLibFolders FROM-CACHE
> Task :mergeCnDebugNativeLibs FROM-CACHE
> Task :stripCnDebugDebugSymbols FROM-CACHE
> Task :packageCnDebug
> Task :transformClassesWithBoosterForCnDebug
> Task :assembleCnDebug
> Task :preCnReleaseBuild UP-TO-DATE
> Task :compileCnReleaseAidl NO-SOURCE
> Task :compileCnReleaseRenderscript NO-SOURCE
> Task :checkCnReleaseManifest
> Task :generateCnReleaseBuildConfig FROM-CACHE
> Task :javaPreCompileCnRelease FROM-CACHE
> Task :mainApkListPersistenceCnRelease
> Task :generateCnReleaseResValues FROM-CACHE
> Task :generateCnReleaseResources UP-TO-DATE
> Task :mergeCnReleaseResources FROM-CACHE
> Task :createCnReleaseCompatibleScreenManifests
> Task :processCnReleaseManifest
> Task :processCnReleaseResources
> Task :compileCnReleaseJavaWithJavac FROM-CACHE
> Task :compileCnReleaseSources UP-TO-DATE
> Task :prepareLintJar
> Task :lintVitalCnRelease FAILED

FAILURE: Build completed with 2 failures.

1:
Task failed with an exception.
-----------
* What went wrong:
Execution failed for task ':lintVitalCnRelease'.
>
Lint infrastructure error
Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.android.tools.lint.gradle.api.ReflectiveLintRunner.runLint(ReflectiveLintRunner.kt:38)
at com.android.build.gradle.tasks.LintBaseTask.runLint(LintBaseTask.java:100)
at com.android.build.gradle.tasks.LintPerVariantTask.lint(LintPerVariantTask.java:60)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:103)
at org.gradle.api.internal.project.taskfactory.StandardTaskAction.doExecute(StandardTaskAction.java:48)
at org.gradle.api.internal.project.taskfactory.StandardTaskAction.execute(StandardTaskAction.java:41)
at org.gradle.api.internal.project.taskfactory.StandardTaskAction.execute(StandardTaskAction.java:28)
at org.gradle.api.internal.AbstractTask$TaskActionWrapper.execute(AbstractTask.java:702)
at org.gradle.api.internal.AbstractTask$TaskActionWrapper.execute(AbstractTask.java:669)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter$5.run(ExecuteActionsTaskExecuter.java:404)
at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:402)
at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:394)
at org.gradle.internal.operations.DefaultBuildOperationExecutor$1.execute(DefaultBuildOperationExecutor.java:165)
at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:250)
at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:158)
at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:92)
at org.gradle.internal.operations.DelegatingBuildOperationExecutor.run(DelegatingBuildOperationExecutor.java:31)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeAction(ExecuteActionsTaskExecuter.java:393)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:376)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.access$200(ExecuteActionsTaskExecuter.java:80)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter$TaskExecution.execute(ExecuteActionsTaskExecuter.java:213)
at org.gradle.internal.execution.steps.ExecuteStep.lambda$execute$1(ExecuteStep.java:33)
at java.util.Optional.orElseGet(Optional.java:267)
at org.gradle.internal.execution.steps.ExecuteStep.execute(ExecuteStep.java:33)
at org.gradle.internal.execution.steps.ExecuteStep.execute(ExecuteStep.java:26)
at org.gradle.internal.execution.steps.CleanupOutputsStep.execute(CleanupOutputsStep.java:58)
at org.gradle.internal.execution.steps.CleanupOutputsStep.execute(CleanupOutputsStep.java:35)
at org.gradle.internal.execution.steps.ResolveInputChangesStep.execute(ResolveInputChangesStep.java:48)
at org.gradle.internal.execution.steps.ResolveInputChangesStep.execute(ResolveInputChangesStep.java:33)
at org.gradle.internal.execution.steps.CancelExecutionStep.execute(CancelExecutionStep.java:39)
at org.gradle.internal.execution.steps.TimeoutStep.executeWithoutTimeout(TimeoutStep.java:73)
at org.gradle.internal.execution.steps.TimeoutStep.execute(TimeoutStep.java:54)
at org.gradle.internal.execution.steps.CatchExceptionStep.execute(CatchExceptionStep.java:35)
at org.gradle.internal.execution.steps.CreateOutputsStep.execute(CreateOutputsStep.java:51)
at org.gradle.internal.execution.steps.SnapshotOutputsStep.execute(SnapshotOutputsStep.java:45)
at org.gradle.internal.execution.steps.SnapshotOutputsStep.execute(SnapshotOutputsStep.java:31)
at org.gradle.internal.execution.steps.CacheStep.executeWithoutCache(CacheStep.java:201)
at org.gradle.internal.execution.steps.CacheStep.execute(CacheStep.java:70)
at org.gradle.internal.execution.steps.CacheStep.execute(CacheStep.java:45)
at org.gradle.internal.execution.steps.BroadcastChangingOutputsStep.execute(BroadcastChangingOutputsStep.java:49)
at org.gradle.internal.execution.steps.StoreSnapshotsStep.execute(StoreSnapshotsStep.java:43)
at org.gradle.internal.execution.steps.StoreSnapshotsStep.execute(StoreSnapshotsStep.java:32)
at org.gradle.internal.execution.steps.RecordOutputsStep.execute(RecordOutputsStep.java:38)
at org.gradle.internal.execution.steps.RecordOutputsStep.execute(RecordOutputsStep.java:24)
at org.gradle.internal.execution.steps.SkipUpToDateStep.executeBecause(SkipUpToDateStep.java:96)
at org.gradle.internal.execution.steps.SkipUpToDateStep.lambda$execute$0(SkipUpToDateStep.java:89)
at java.util.Optional.map(Optional.java:215)
at org.gradle.internal.execution.steps.SkipUpToDateStep.execute(SkipUpToDateStep.java:54)
at org.gradle.internal.execution.steps.SkipUpToDateStep.execute(SkipUpToDateStep.java:38)
at org.gradle.internal.execution.steps.ResolveChangesStep.execute(ResolveChangesStep.java:77)
at org.gradle.internal.execution.steps.ResolveChangesStep.execute(ResolveChangesStep.java:37)
at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsFinishedStep.execute(MarkSnapshottingInputsFinishedStep.java:36)
at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsFinishedStep.execute(MarkSnapshottingInputsFinishedStep.java:26)
at org.gradle.internal.execution.steps.ResolveCachingStateStep.execute(ResolveCachingStateStep.java:90)
at org.gradle.internal.execution.steps.ResolveCachingStateStep.execute(ResolveCachingStateStep.java:48)
at org.gradle.internal.execution.impl.DefaultWorkExecutor.execute(DefaultWorkExecutor.java:33)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:120)
at org.gradle.api.internal.tasks.execution.ResolveBeforeExecutionStateTaskExecuter.execute(ResolveBeforeExecutionStateTaskExecuter.java:75)
at org.gradle.api.internal.tasks.execution.ValidatingTaskExecuter.execute(ValidatingTaskExecuter.java:62)
at org.gradle.api.internal.tasks.execution.SkipEmptySourceFilesTaskExecuter.execute(SkipEmptySourceFilesTaskExecuter.java:108)
at org.gradle.api.internal.tasks.execution.ResolveBeforeExecutionOutputsTaskExecuter.execute(ResolveBeforeExecutionOutputsTaskExecuter.java:67)
at org.gradle.api.internal.tasks.execution.StartSnapshotTaskInputsBuildOperationTaskExecuter.execute(StartSnapshotTaskInputsBuildOperationTaskExecuter.java:62)
at org.gradle.api.internal.tasks.execution.ResolveAfterPreviousExecutionStateTaskExecuter.execute(ResolveAfterPreviousExecutionStateTaskExecuter.java:46)
at org.gradle.api.internal.tasks.execution.CleanupStaleOutputsExecuter.execute(CleanupStaleOutputsExecuter.java:94)
at org.gradle.api.internal.tasks.execution.FinalizePropertiesTaskExecuter.execute(FinalizePropertiesTaskExecuter.java:46)
at org.gradle.api.internal.tasks.execution.ResolveTaskExecutionModeExecuter.execute(ResolveTaskExecutionModeExecuter.java:95)
at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:57)
at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:56)
at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:36)
at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.executeTask(EventFiringTaskExecuter.java:73)
at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:52)
at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:49)
at org.gradle.internal.operations.DefaultBuildOperationExecutor$CallableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:416)
at org.gradle.internal.operations.DefaultBuildOperationExecutor$CallableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:406)
at org.gradle.internal.operations.DefaultBuildOperationExecutor$1.execute(DefaultBuildOperationExecutor.java:165)
at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:250)
at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:158)
at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:102)
at org.gradle.internal.operations.DelegatingBuildOperationExecutor.call(DelegatingBuildOperationExecutor.java:36)
at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter.execute(EventFiringTaskExecuter.java:49)
at org.gradle.execution.plan.LocalTaskNodeExecutor.execute(LocalTaskNodeExecutor.java:43)
at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:355)
at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:343)
at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:336)
at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:322)
at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker$1.execute(DefaultPlanExecutor.java:134)
at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker$1.execute(DefaultPlanExecutor.java:129)
at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.execute(DefaultPlanExecutor.java:202)
at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.executeNextNode(DefaultPlanExecutor.java:193)
at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.run(DefaultPlanExecutor.java:129)
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:63)
at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:46)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:55)
at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.OutOfMemoryError: Metaspace
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:756)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:468)
at java.net.URLClassLoader.access$100(URLClassLoader.java:74)
at java.net.URLClassLoader$1.run(URLClassLoader.java:369)
at java.net.URLClassLoader$1.run(URLClassLoader.java:363)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:362)
at com.android.tools.lint.gradle.api.DelegatingClassLoader.findClass(DelegatingClassLoader.kt:30)
at java.lang.ClassLoader.loadClass(ClassLoader.java:418)
at java.lang.ClassLoader.loadClass(ClassLoader.java:351)
at com.android.tools.lint.checks.BuiltinIssueRegistry.<clinit>(BuiltinIssueRegistry.java:363)
at com.android.tools.lint.gradle.LintGradleExecution.createIssueRegistry(LintGradleExecution.java:375)
at com.android.tools.lint.gradle.LintGradleExecution.runLint(LintGradleExecution.java:216)
at com.android.tools.lint.gradle.LintGradleExecution.lintSingleVariant(LintGradleExecution.java:385)
at com.android.tools.lint.gradle.LintGradleExecution.analyze(LintGradleExecution.java:91)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.android.tools.lint.gradle.api.ReflectiveLintRunner.runLint(ReflectiveLintRunner.kt:38)
at com.android.build.gradle.tasks.LintBaseTask.runLint(LintBaseTask.java:100)
at com.android.build.gradle.tasks.LintPerVariantTask.lint(LintPerVariantTask.java:60)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:103)
at org.gradle.api.internal.project.taskfactory.StandardTaskAction.doExecute(StandardTaskAction.java:48)
at org.gradle.api.internal.project.taskfactory.StandardTaskAction.execute(StandardTaskAction.java:41)
at org.gradle.api.internal.project.taskfactory.StandardTaskAction.execute(StandardTaskAction.java:28)


* Try:

Run with
--info
or
--debug
option to get more log output. Run with
--scan
to get full insights.

从上面的堆栈来看,是 lintVitalCnRelease 这个 Task 的锅,于是,尝试关掉 lintVitalCnRelease

1
2
3
4
5
6
7
8
android {

...

lintOptions {
checkReleaseBuilds false
}
}

再次 run 一下测试用例,通过 VisualVM 分析,发现 Metaspace 的增长曲线变成这样了:

Normal Metaspace

当然,除了禁用 lintVital 的方式外,还可以通过 gradle.properties 来调大 Metaspace 的大小:

1
org.gradle.jvmargs=-XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -Xms512m -Xmx2048m