From 1c21f13b990c652acd17abefee69e26ec13d1511 Mon Sep 17 00:00:00 2001 From: Ethan Atkins Date: Sun, 23 Aug 2020 16:58:05 -0700 Subject: [PATCH] Reduce sbt memory utilization The sbt Server is initialized with a callback onIncomingSocket. That callback was created in CommandExchange and held references to a build structure and a state. Neither the state nor structure would ever go out of scope so they effectively leaked. It is possible for each NetworkChannel to access a recent instance of state through the CommandExchange.withState method. Using this, we can eliminate the references to state and build structure in the onIncomingSocket callback. In the sbt project, this reduced the memory utilization by about 50mb on startup. --- .../scala/sbt/internal/CommandExchange.scala | 3 --- .../sbt/internal/server/NetworkChannel.scala | 21 ++++++++++--------- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/main/src/main/scala/sbt/internal/CommandExchange.scala b/main/src/main/scala/sbt/internal/CommandExchange.scala index 7b3b48901..58ec187fd 100644 --- a/main/src/main/scala/sbt/internal/CommandExchange.scala +++ b/main/src/main/scala/sbt/internal/CommandExchange.scala @@ -195,13 +195,10 @@ private[sbt] final class CommandExchange { new NetworkChannel( name, socket, - Project structure s, auth, instance, handlers, - s.log, mkAskUser(name), - Option(lastState.get), ) subscribe(channel) } diff --git a/main/src/main/scala/sbt/internal/server/NetworkChannel.scala b/main/src/main/scala/sbt/internal/server/NetworkChannel.scala index 1c7d93484..7bf6d2727 100644 --- a/main/src/main/scala/sbt/internal/server/NetworkChannel.scala +++ b/main/src/main/scala/sbt/internal/server/NetworkChannel.scala @@ -54,13 +54,10 @@ import sbt.internal.util.ProgressState final class NetworkChannel( val name: String, connection: Socket, - protected val structure: BuildStructure, auth: Set[ServerAuthentication], instance: ServerInstance, handlers: Seq[ServerHandler], - val log: Logger, mkUIThreadImpl: (State, CommandChannel) => UITask, - state: Option[State], ) extends CommandChannel { self => def this( name: String, @@ -74,15 +71,14 @@ final class NetworkChannel( this( name, connection, - structure, auth, instance, handlers, - log, new UITask.AskUserTask(_, _), - None ) + def log: Logger = StandardMain.exchange.withState(_.log) + private val running = new AtomicBoolean(true) private val delimiter: Byte = '\n'.toByte private val out = connection.getOutputStream @@ -411,9 +407,12 @@ final class NetworkChannel( protected def onSettingQuery(execId: Option[String], req: SettingQuery) = { if (initialized) { import sbt.protocol.codec.JsonProtocol._ - SettingQuery.handleSettingQueryEither(req, structure) match { - case Right(x) => respondResult(x, execId) - case Left(s) => respondError(ErrorCodes.InvalidParams, s, execId) + StandardMain.exchange.withState { s => + val structure = Project.extract(s).structure + SettingQuery.handleSettingQueryEither(req, structure) match { + case Right(x) => respondResult(x, execId) + case Left(s) => respondError(ErrorCodes.InvalidParams, s, execId) + } } } else { log.warn(s"ignoring query $req before initialization") @@ -792,7 +791,9 @@ final class NetworkChannel( private[this] val blockedThreads = ConcurrentHashMap.newKeySet[Thread] override private[sbt] val progressState: ProgressState = new ProgressState( 1, - state.flatMap(_.get(Keys.superShellMaxTasks.key)).getOrElse(SysProp.supershellMaxTasks) + StandardMain.exchange + .withState(_.get(Keys.superShellMaxTasks.key)) + .getOrElse(SysProp.supershellMaxTasks) ) override def getWidth: Int = getProperty(_.width, 0).getOrElse(0) override def getHeight: Int = getProperty(_.height, 0).getOrElse(0)