我参与了一个包含多个java gradle模块的项目。其中两个最近合并,显着提高了编译时间。我读过使用推断的泛型和重载方法会增加编译时间。
是否有任何工具可以帮助在Java中找到慢编译时类?还是一个指出潜在速度陷阱的短绒?
答案 0 :(得分:0)
我一直在寻找一种方法来做同样的事情,不得不想出我自己的方法,我将在下面描述。
首先,请注意,当您使用 javac
编译类时,您可以传递 -verbose
标志,以便编译器记录正在发生的一切(它将输出发送到 stderr)。
在 Gradle 中,您可以将该选项传递给编译器,如下所示:
compileJava {
options.verbose = true
}
我的 hello world 课程看起来像这样(隐藏了很多不相关的东西):
[parsing started SimpleFileObject[/Users/renato/programming/experiments/java/Main.java]]
[parsing completed 21ms]
[loading /modules/jdk.jsobject/module-info.class]
[loading /modules/jdk.management/module-info.class]
...
[checking Main]
[loading /modules/java.base/java/io/Serializable.class]
[loading /modules/java.base/java/lang/AutoCloseable.class]
[loading /modules/java.base/java/lang/Class.class]
[loading /modules/java.base/java/lang/System.class]
[loading /modules/java.base/java/io/PrintStream.class]
[loading /modules/java.base/java/lang/Appendable.class]
[loading /modules/java.base/java/io/Closeable.class]
[loading /modules/java.base/java/io/FilterOutputStream.class]
[loading /modules/java.base/java/io/OutputStream.class]
[loading /modules/java.base/java/io/Flushable.class]
[wrote Main.class]
[total 229ms]
如您所见,您可以捕获 stderr,然后计算它显示 parsing started ...Main.java
和 wrote Main.class
之间的时间。
如果您跟踪每个源文件和等效类文件的消息,您应该能够获得有关编译每个类所用时间的准确信息。
不幸的是,我认为 Gradle 不允许我们使用 Java 编译器的输出,因此我们需要使用其他东西来为我们运行 Gradle 并解析该输出。
这是一个使用 Groovy 脚本执行此操作的示例(即使在 Windows 中,只需稍作修改即可,或者仅使用 javac
或 mvn
进行编译):
def projectDir = new File(System.getProperty('user.home') + '/programming/experiments/gradle')
def javaSourcesRoot = new File(projectDir, 'src/main/java').absolutePath
def classFilesRoot = new File(projectDir, 'build/classes/java/main').absolutePath
def sourcesPrefix = "[parsing started SimpleFileObject[$javaSourcesRoot/"
def donePrefix = "[wrote $classFilesRoot/"
log "Starting Gradle"
def gradle = ['gradle', 'compileJava'].execute((List) null, projectDir)
def stdout = new StringBuilder()
def stderr = new StringBuilder()
gradle.consumeProcessOutput(stdout, stderr)
assert gradle.waitFor() == 0: "$stdout\n$stderr"
def classInfo = [:]
stderr.eachLine { line ->
if (line.startsWith(sourcesPrefix)) {
def className = (line - sourcesPrefix - '.java]]').replaceAll(File.separator, '.')
log "Started compiling class $className"
classInfo[className] = [startTime: System.currentTimeMillis()]
}
if (line.startsWith(donePrefix)) {
def className = (line - donePrefix - '.class]').replaceAll('/', '.')
log "Done compiling class $className"
classInfo[className].endTime = System.currentTimeMillis()
}
}
def results = classInfo.collect { String className, Map info ->
"${className.padRight(20)} ${info.endTime - info.startTime}"
}.join('\n')
log "Results:\n$results"
void log(msg) {
println "${new Date()} - $msg"
}
我的小型示例项目的结果:
Fri Jul 23 16:39:18 CEST 2021 - Starting Gradle
Fri Jul 23 16:39:20 CEST 2021 - Started compiling class other.JavaType
Fri Jul 23 16:39:20 CEST 2021 - Started compiling class my.Main
Fri Jul 23 16:39:20 CEST 2021 - Done compiling class other.JavaType
Fri Jul 23 16:39:20 CEST 2021 - Done compiling class my.Main
Fri Jul 23 16:39:20 CEST 2021 - Results:
other.JavaType 9
my.Main 4
时间以毫秒为单位,所以 my.Main
是一个 hello world 类,编译需要 9 毫秒……other.JavaType
是一个空类,需要 4 毫秒。