当前位置: 首页 > 知识库问答 >
问题:

Akka http内存泄漏(带有web套接字)

严开宇
2023-03-14

我有一个web服务器,它接受传入的websocket连接,在Scala中用akka http实现。然而,我一直观察到我的应用程序的内存使用量单调增加。经过长时间的挖掘,我发现每个连接都会创建一些内部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计算对象计数,并注意到每个连接都有一个严格的新对象。我试着用成千上万的连接,同样的事情发生了。

我使用这个命令来计算对象的数量:

jmap-histo:Live[pid]grep ActorGraphInterpreter

下面是启动时以及打开和关闭1000个连接后的结果

您可以看到,对象计数严格按连接数增加。我确保我的客户端已断开连接--我关闭了进程,并用netstat验证连接已关闭。

共有1个答案

司英飙
2023-03-14

您可能没有考虑到Scala基于JVM,而JVM使用垃圾回收器,而垃圾回收器又不是确定性的。特别是如果您没有产生足够的内存压力(与允许的内存限制相比),GC可能根本无法运行。您可以通过强制使用GC来轻松验证这个理论(GC在生产中很可能很糟糕,但可以进行调试)。尝试在main方法的开头添加以下代码:

new Thread() {
  override def run(): Unit = {
    println("Start GC-thread")
    val start = System.currentTimeMillis()
    while (true) {
      Thread.sleep(1000)
      System.gc()
    }
  }
}.start()

这段代码启动了一个独立的线程,该线程将要求VM每秒执行GC。我敢打赌,使用这样的代码,您的测试只会显示几个活动的ActorGraphInterpreter对象。至少这是我在你的例子中看到的。如果您在实际代码中仍然看到许多actorGraphInterpreter,那么您的示例可能是一个不足的MCVE,您应该发布一个更好的MCVE。

 类似资料:
  • 我所采用的方法是将创建、使用和关闭套接字的整个部分推进到一个函数中--在完成这些操作后,依赖Python的垃圾收集来删除每个实例: 我的问题是:(1)这种方法能避免任何内存泄漏吗?(2)有没有更直接的方法来确保每个实例在我完成后都被消除?

  • 问题内容: 我认为我的android应用正在泄漏内存。我不是绝对确定这是问题所在。 应用程序打开时经常崩溃,并且logcat尝试加载位图图像时会显示“内存不足”异常。 崩溃后,我重新打开了该应用程序,它运行正常。Logcat会显示许多“ gc”,并且JIT表会不时地向上调整大小,而不会向下调整,直到应用程序因内存不足错误而崩溃。 这听起来像是内存泄漏吗?如果是这样,我该如何定位和关闭泄漏点。 这是

  • 问题内容: 我一直在追寻内存泄漏(由“ valgrind –leak-check = yes”报告),它似乎来自ALSA。这段代码已经存在于自由世界中一段时间​​了,所以我猜这是我做错的事情。 输出看起来像这样: 并继续一些页面 这是由于我在一个项目中使用ALSA并开始看到这种巨大的泄漏……或者至少是所说泄漏的报告。 所以问题是:是我,ALSA或valgrind在这里遇到问题吗? 问题答案: ht

  • 问题内容: 我有一个长时间运行的脚本,如果让脚本运行足够长的时间,它将消耗系统上的所有内存。 在不详细介绍脚本的情况下,我有两个问题: 是否有可遵循的“最佳实践”,以防止泄漏发生? 有什么技术可以调试Python中的内存泄漏? 问题答案: 看看这篇文章:跟踪python内存泄漏 另外,请注意,垃圾收集模块实际上可以设置调试标志。看一下功能。此外,请查看Gnibbler的这段代码,以确定调用后已创建

  • 本文向大家介绍Java 内存泄漏,包括了Java 内存泄漏的使用技巧和注意事项,需要的朋友参考一下 在Java中,垃圾回收(析构函数的工作)是使用垃圾回收自动完成的。但是,如果代码中有引用它们的对象怎么办?它无法取消分配,即无法清除其内存。如果这种情况一再发生,并且创建或引用的对象根本没有被使用,它们就会变得无用。这就是所谓的内存泄漏。 如果超过了内存限制,则程序将通过抛出错误(即“ OutOfM

  • 问题内容: 我使用Informix遇到了一个奇怪的问题(具体来说,我使用的是IBM.Data.Informix命名空间,即4.10 Client SDK)。我正在使用ODBC连接到IBM Informix数据库,并且遇到内存泄漏问题。该文档相当稀疏,并且我只能使用当前安装的驱动程序/ SDK。这是我用于数据库上下文的代码: } 我已尝试处置并关闭所有可以的连接,但这似乎无济于事。我是否缺少某些东西