akka 演员如何清理资源?

ru9i0ody  于 2022-11-06  发布在  其他
关注(0)|答案(1)|浏览(208)

我们在使用Akka HTTP构建的Web服务器上遇到了奇怪的内存行为。我们的架构如下所示:

  1. web服务器路由呼叫各个参与者,获取结果以备将来使用,并将其流式传输到响应
  2. actors调用非阻塞操作(使用future),合并并处理从它们获取的数据,并将结果通过管道发送到发送方。我们使用标准的Akka actors,实现其接收方法(不是Akka类型的)
    1.应用程序中没有任何阻止代码
    当我在本地运行web服务器时,一开始大约需要350 MB。在第一次请求后,内存使用量会跳到430 MB左右,并且随着每次请求而缓慢增加(使用Mac上的Activity Monitor进行监控)。但是GC不应该在每次请求后清理内容吗?处理后的内存使用量不应该再次达到350 MB吗?
    我还安装了YourKit java profiler,下面是头部内存的图

可以看出,一旦内存使用增加,它就再也不会回来了,系统是无状态的。而且,当我从分析器手动运行GC时,它几乎什么也不做,只是内存使用略有减少。我知道有些服务可能会在第一次请求后缓存内容,暂时消耗内存,但Akka Actors或Akka HTTP内部有关于这方面的任何策略吗?
我试图检查离GC最远的对象,但它只显示库类和Akka内置类,与我们的代码无关。
所以,我有两个问题:
1.在消息处理之后,参与者是如何关闭资源并释放内存的?你有类似的经历吗?
1.有没有更好的分析Akka HTTP的方法,它可以显示使用离GC最远的类的堆栈跟踪?
顺便说一句,在Actor内部使用调度程序(在Akka HTTP服务器内部运行)是否可取?当我这样做时,内存使用量似乎大幅增加,应用程序在DEV环境中运行内存。
先谢谢你,
阿梅尔

5gfr0r5j

5gfr0r5j1#

执行元将保持活动状态,直到被显式停止:不存在垃圾收集。
管理参与者生命周期(除了参与者自己决定是时候停止之外)最常用的两种方法可能是:

  • 父级负责停止子级。例如,如果生成执行元以代表父级执行特定任务,则需要此方法。
  • 使用非活动超时。如果参与者表示域实体(例如,每个用户帐户的行动者,其中该行动者在某种意义上用作存储器内高速缓存),使用context.setReceiveTimeout使ReceiveTimeout消息在超时后发送到执行元(注意,在某些情况下,如果消息已在邮箱中排队但在超时到期时未被处理,则该消息的计划发送可能不会被及时取消:接收ReceiveTimeout并不能保证自上次接收消息以来已经过了超时)是一个相当合理的解决方案,尤其是在使用Akka持久性和Akka集群分片来允许恢复参与者的状态时。

更新以添加:
关于
GC不应该在每次请求后进行清理吗?
简单地说,答案是否定的,GC不会在每次请求后清理内容(如果它清理了内容,这是一个很好的迹象,表明您没有提供足够的内存)。
较长的答案是JVM上垃圾收集的特征被非常不明确地规定了:垃圾收集实现必须遵守的唯一规则是它从不释放从GC根可达的对象(基本上是线程堆栈上的任何变量或类的静态变量)。垃圾回收器何时回收垃圾所占用的空间,甚至回收是否回收垃圾所占用的空间,都完全取决于实现(我说“是否”是为了说明Epsilon垃圾收集器的存在,它永远不会释放内存;这对于在没有垃圾收集复杂性的情况下对JVM进行基准测试以及在应用程序用完内存时可以重新启动的环境中非常有用:JVM崩溃在某种意义上就是实际的垃圾收集器)。
您可以尝试在服务器停止时执行java.lang.System.gc:这可能会导致GC运行(注意,在这种情况下,系统实际上并不需要收集任何垃圾)。如果垃圾收集器要释放任何内存,那么只有在没有足够的空间来满足对象分配请求时,它才必须运行:因此,如果应用程序停止分配对象,则可能没有垃圾收集运行。
出于性能原因,JVM中的大多数现代垃圾收集器都会等到空闲空间不超过一定量时才收集垃圾:这是因为回收所有空间所花费的时间与不可回收的对象的数量成比例,并且对于很多应用程序来说,模式是大多数对象是相对短暂的,因此不可回收的对象数量是相当恒定的。其结果是垃圾收集器将在“完全”状态下执行大约相同数量的工作。无论有多少可用空间,都可以为给定的应用程序执行GC。

相关问题