У меня есть веб-сервер, который принимает входящее соединение через веб-сервер, реализованный с помощью akka http в Scala. Однако я наблюдал монотонное увеличение использования памяти моим приложением. После долгих поисков я обнаружил, что некоторые внутренние объекты Akka создаются при каждом подключении, но не очищаются после отключения клиента. Специально этот класс: akka.stream.impl.fusing.ActorGraphInterpreter. Для каждого соединения создается один новый такой объект. Я использовал jmap для подсчета количества объектов, команда приведена ниже. Не уверен, что я здесь что-то не так делаю. Любые советы будут высоко ценится.
У меня есть супер простой сервер echo websocket, чтобы воспроизвести это наблюдение:
package samples
import akka.actor.ActorSystem
import akka.http.scaladsl.Http
import akka.http.scaladsl.model.ws.{Message, TextMessage}
import akka.http.scaladsl.server.Directives._
import akka.stream.ActorMaterializer
import akka.stream.scaladsl.{Flow, Source}
import scala.concurrent.ExecutionContext.Implicits.global
import scala.io.StdIn
object AkkaWsExample {
implicit val system = ActorSystem()
implicit val materializer = ActorMaterializer()
private val greeterWebSocketService = {
Flow[Message]
.collect {
case tm: TextMessage =>
println(s"Received $tm")
TextMessage(Source.single("Hello ") ++ tm.textStream)
}
}
def main(args: Array[String]): Unit = {
//#websocket-routing
val route =
path("greeter") {
get {
handleWebSocketMessages(greeterWebSocketService)
}
}
val bindingFuture = Http().bindAndHandle(route, "localhost", 8080)
println(s"Server online at http://localhost:8080/\nPress RETURN to stop...")
StdIn.readLine() // for the future transformations
bindingFuture
.flatMap(_.unbind()) // trigger unbinding from the port
.onComplete(_ => system.terminate()) // and shutdown when done
}
}
Затем я использовал любой метод для подключения к этому серверу и отключения, и запустил jmap для подсчета количества объектов и заметил строго 1 новый объект на каждое соединение. Я пробовал это с тысячами подключений, происходит то же самое.
Я использовал эту команду для подсчета количества объектов:
jmap -histo:live [pid] | grep ActorGraphInterpreter
Вот результаты при запуске и после открытия и закрытия 1000 подключений
ip-192-168-30-10:~ liuh$ jps | grep Akka | awk '{print $1}' | xargs jmap -histo:live | grep ActorGraphInt | head -n1
701: 1 56 akka.stream.impl.fusing.ActorGraphInterpreter
ip-192-168-30-10:~ liuh$ jps | grep Akka | awk '{print $1}' | xargs jmap -histo:live | grep ActorGraphInt | head -n1
119: 1001 56056 akka.stream.impl.fusing.ActorGraphInterpreter
Вы можете видеть, что количество объектов увеличивается строго на количество подключений. Я убедился, что моя клиентская сторона отключена - я закрыл процессы, а также проверил с помощью netstat, что соединения были отключены.





Вы, вероятно, не учитываете тот факт, что Scala основана на JVM, которая использует сборщик мусора, который, в свою очередь, не является детерминированным. В частности, если вы не создаете достаточной нагрузки на память (по сравнению с допустимым пределом памяти), сборщик мусора может вообще не работать. Вы можете легко проверить эту теорию, принудительно запустив сборку мусора (что в большинстве случаев, вероятно, плохо в производственной среде, но подходит для отладки). Попробуйте добавить в начало вашего метода main следующий код:
new Thread() {
override def run(): Unit = {
println("Start GC-thread")
val start = System.currentTimeMillis()
while (true) {
Thread.sleep(1000)
System.gc()
}
}
}.start()
Этот код запускает независимый поток, который будет просить виртуальную машину выполнять сборку мусора каждую секунду. Готов поспорить, что с таким кодом ваш тест покажет не более нескольких живых объектов ActorGraphInterpreter. По крайней мере, это то, что я вижу в вашем примере. Если вы все еще видите много ActorGraphInterpreter в своем реальном коде, ваш пример, вероятно, является неадекватным MCVE, и вам следует опубликовать лучший вариант.
Привет. Какую версию вы используете? У меня точно такая же проблема
@ user1861088, последний вопрос наверное адресован вам
Спасибо за предложение. jmap -histo: live фактически вызывает полный сборщик мусора. Я разобрался в проблеме. Это ошибка в akka-http. Версия, которую я использовал, была лишь той, где это было введено, но еще не исправлено. github.com/akka/akka-http/issues/2067