Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/19.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala 使用Akka角色时发生OutOfMemoryError_Scala_Rabbitmq_Akka_Actor - Fatal编程技术网

Scala 使用Akka角色时发生OutOfMemoryError

Scala 使用Akka角色时发生OutOfMemoryError,scala,rabbitmq,akka,actor,Scala,Rabbitmq,Akka,Actor,我有一个使用RabbitMQ消息的应用程序,我正在使用参与者来处理这项工作 我的做法如下: object QueueConsumer extends Queue { def consumeMessages = { setupListener(buildChannel(resultsQueueName), resultsQueueName, resultsCallback) } private def setupListener(receivingChann

我有一个使用RabbitMQ消息的应用程序,我正在使用参与者来处理这项工作

我的做法如下:

object QueueConsumer extends Queue {

  def consumeMessages = {
    setupListener(buildChannel(resultsQueueName), resultsQueueName,
        resultsCallback)
  }

  private def setupListener(receivingChannel: Channel, queue: String, 
        f: (String) => Any) {
    Akka.system.scheduler.scheduleOnce(Duration(10, TimeUnit.SECONDS),
      Akka.system.actorOf(Props(new QueueActor(receivingChannel, queue, f))), "")
  }

}

class QueueActor(channel:Channel, queue:String, f:(String) => Any) extends Actor{

  def receive = {
    case _ => startReceiving
  }

  def startReceiving = {
    val consumer = new QueueingConsumer(channel)
    channel.basicConsume(queue, false, consumer)
    while (true) {
      val delivery = consumer.nextDelivery()
      val msg = new String(delivery.getBody())
      context.actorOf(Props(new Actor {
    def receive = {
      case some: String => f(some)
    }
      })) ! msg
      channel.basicAck(delivery.getEnvelope.getDeliveryTag, false)
    }
  }

}
运行几秒钟后,它抛出一个java.lang.OutOfMemoryError:超出了GC开销限制

我认为这是因为我为收到的每一条消息都要开始一个新的参与者——所以如果我有100000条消息,它将创建100000个参与者。这是一个好方法还是应该实现类似“参与者池”的东西

有人知道如何在我的场景中避免OutOfMemory错误吗

先谢谢你

编辑1:

改变方法:

class Queue2(json:String) extends Actor {

  def receive = {
    case x: String =>
      val envelope = MessageEnvelopeParser.toObject(x)
      val processor = ProcessQueueServiceFactory.getProcessResultsService()
      envelope.messages.foreach(message => processor.process(message))
  }

}

object Queue2 {
  def props(json: String): Props = Props(new Queue2(json))
}

class QueueActor(channel:Channel, queue:String) extends Actor {

  def receive = {
    case _ => startReceiving
  }

  def startReceiving = {
    val consumer = new QueueingConsumer(channel)
    channel.basicConsume(queue, false, consumer)
    while (true) {
      val delivery = consumer.nextDelivery()
      val msg = new String(delivery.getBody())
      context.actorOf(Queue2.props(msg))
      channel.basicAck(delivery.getEnvelope.getDeliveryTag, false)
    }
  }
}

完成后,您的每封邮件的参与者将需要停止自己,否则他们将永远留在您身边。请参阅和上的文档。在这里,您只需添加
上下文。在处理完成后停止(self)

为每条消息创建一个新的
参与者
并不一定是糟糕的设计。这不应该让你的记忆耗尽,除非你以某种方式保留着演员或消息的每一个引用,这样GCer就无法收集它们。@Samuel我怎么能检查它?当actor调用回调函数(f)时,它会在sqlserver上执行一些查询(比如INSERT/SELECT,但都是简单的命令)。当回调完成时,是否需要实现一些东西来“杀死”参与者?我是一个新使用Actors的人。看起来Akka保留了您传递给
actorOf()
的每个actor的引用。因此,似乎不应该为每个排队的消息创建新的参与者。我认为您应该有一个actor来执行SQL命令,并让您的
QueueActor
从队列中读取命令并将命令发送给SQL执行器actor。如果你真的想做你现在正在做的事情,你可以使用Akka.system.stop()杀死一个演员引用。@Samuel我尝试过另一种方法,但同样的错误。你能检查一下我在这个主题上所做的这个版本,并检查它是否是你所说的吗?你有没有尝试将嵌套的
Actor
放在
QueueActor
传递
f:(String=>Any)
ass构造函数参数之外?我似乎记得有人说过,通过闭包将一个
参与者
的字段暴露给另一个
参与者
是个坏主意。另外,(只是一个预感),而不是在代码中阻塞.>接收< /代码>,您可以考虑使用未来来接收消息并在代码>未来中创建消息角色。