Call System.gc only when when log level is debug, fixes KT-11022

This commit is contained in:
Alexey Tsvetkov
2016-02-12 20:41:19 +01:00
committed by Ilya Chernikov
parent bc5110550a
commit d0efd4083f
4 changed files with 52 additions and 30 deletions
@@ -21,12 +21,7 @@ import org.gradle.BuildAdapter
import org.gradle.BuildResult
import org.gradle.api.logging.Logging
import java.util.concurrent.ScheduledExecutorService
internal fun getUsedMemoryKb(): Long {
System.gc()
val rt = Runtime.getRuntime()
return (rt.totalMemory() - rt.freeMemory()) / 1024
}
import kotlin.properties.Delegates
private fun comparableVersionStr(version: String) =
@@ -39,13 +34,23 @@ private fun comparableVersionStr(version: String) =
?.let { if (it.all { (it?.value?.length ?: 0).let { it > 0 && it < 4 }}) it else null }
?.joinToString(".", transform = { it!!.value.padStart(3, '0') })
class CleanUpBuildListener(pluginClassLoader: ClassLoader) : BuildAdapter() {
companion object {
const val FORCE_SYSTEM_GC_MESSAGE = "Forcing System.gc()"
}
class FinishBuildListener(pluginClassLoader: ClassLoader, val startMemory: Long) : BuildAdapter() {
val log = Logging.getLogger(this.javaClass)
private val log = Logging.getLogger(this.javaClass)
private var threadTracker: ThreadTracker? = ThreadTracker()
private val cleanup = CompilerServicesCleanup(pluginClassLoader)
private var startMemory: Long? = null
// There is function with the same name in BuildAdapter,
// but it is called before any plugin can attach build listener
fun buildStarted() {
if (log.isDebugEnabled) {
startMemory = getUsedMemoryKb()!!
}
}
override fun buildFinished(result: BuildResult?) {
log.kotlinDebug("Build finished listener")
@@ -60,9 +65,22 @@ class FinishBuildListener(pluginClassLoader: ClassLoader, val startMemory: Long)
gradle.removeListener(this)
}
// the value reported here is not necessarily a leak, since it is calculated before collecting the plugin classes
// but on subsequent runs in the daemon it should be rather small, then the classes are actually reused by the daemon (see above)
getUsedMemoryKb().let { log.kotlinDebug("[PERF] Used memory after build: $it kb (${"%+d".format(it - startMemory)} kb)") }
startMemory?.let { startMemoryCopy ->
getUsedMemoryKb()?.let { endMemory ->
// the value reported here is not necessarily a leak, since it is calculated before collecting the plugin classes
// but on subsequent runs in the daemon it should be rather small, then the classes are actually reused by the daemon (see above)
log.kotlinDebug("[PERF] Used memory after build: $endMemory kb (difference since build start: ${"%+d".format(endMemory - startMemoryCopy)} kb)")
}
}
}
private fun getUsedMemoryKb(): Long? {
if (!log.isDebugEnabled) return null
log.lifecycle(FORCE_SYSTEM_GC_MESSAGE)
System.gc()
val rt = Runtime.getRuntime()
return (rt.totalMemory() - rt.freeMemory()) / 1024
}
}
@@ -2,18 +2,10 @@ package org.jetbrains.kotlin.gradle.plugin
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.artifacts.dsl.DependencyHandler
import org.gradle.api.artifacts.ConfigurationContainer
import java.net.URL
import org.gradle.api.logging.Logging
import java.util.Properties
import java.io.FileNotFoundException
import org.gradle.api.initialization.dsl.ScriptHandler
import org.gradle.api.invocation.Gradle
import org.gradle.api.logging.Logger
import java.lang.reflect.Method
import org.gradle.api.logging.Logging
import org.jetbrains.kotlin.gradle.tasks.KotlinTasksProvider
import java.net.URLClassLoader
// TODO: simplify: the complicated structure is a leftover from dynamic loading of plugin core, could be significantly simplified now
@@ -21,9 +13,10 @@ abstract class KotlinBasePluginWrapper: Plugin<Project> {
val log = Logging.getLogger(this.javaClass)
public override fun apply(project: Project) {
val startMemory = getUsedMemoryKb()
override fun apply(project: Project) {
val cleanUpBuildListener = CleanUpBuildListener(this.javaClass.classLoader)
cleanUpBuildListener.buildStarted()
project.gradle.addBuildListener(cleanUpBuildListener)
val sourceBuildScript = findSourceBuildScript(project)
if (sourceBuildScript == null) {
@@ -38,7 +31,6 @@ abstract class KotlinBasePluginWrapper: Plugin<Project> {
val plugin = getPlugin(this.javaClass.classLoader, sourceBuildScript)
plugin.apply(project)
project.gradle.addBuildListener(FinishBuildListener(this.javaClass.classLoader, startMemory))
}
protected abstract fun getPlugin(pluginClassLoader: ClassLoader, scriptHandler: ScriptHandler): Plugin<Project>
@@ -1,9 +1,7 @@
package org.jetbrains.kotlin.gradle
import org.junit.Test
import org.jetbrains.kotlin.gradle.BaseGradleIT.Project
import org.gradle.api.logging.LogLevel
import org.junit.Ignore
import org.junit.Test
class SimpleKotlinGradleIT : BaseGradleIT() {
@@ -1,6 +1,7 @@
package org.jetbrains.kotlin.gradle
import org.jetbrains.kotlin.gradle.BaseGradleIT.Project
import org.gradle.api.logging.LogLevel
import org.jetbrains.kotlin.gradle.plugin.CleanUpBuildListener
import org.junit.Test
class KotlinGradleIT: BaseGradleIT() {
@@ -81,6 +82,19 @@ class KotlinGradleIT: BaseGradleIT() {
}
}
@Test
fun testLogLevelForceGC() {
val debugProject = Project("simpleProject", "1.12", minLogLevel = LogLevel.DEBUG)
debugProject.build("build") {
assertContains(CleanUpBuildListener.FORCE_SYSTEM_GC_MESSAGE)
}
val infoProject = Project("simpleProject", "1.12", minLogLevel = LogLevel.INFO)
infoProject.build("clean", "build") {
assertNotContains(CleanUpBuildListener.FORCE_SYSTEM_GC_MESSAGE)
}
}
@Test
fun testKotlinClasspath() {
Project("classpathTest", "1.6").build("build") {