Akka Stream应用程序使用的内存多于JVM的堆

iyr7buue  于 2022-12-13  发布在  其他
关注(0)|答案(1)|浏览(161)

摘要:

我有一个使用akka流的Java应用程序,它使用的内存比我指定的jvm要多。下面的值是我通过JAVA_OPTS设置的。

  • 最大堆大小(-Xmx)= 700 MB
  • 元空间(-XX)= 250 MB
  • 堆栈大小(-Xss)= 1025 kb

使用这些值并将它们代入下面的公式,可以假设应用程序将使用大约950 MB。但事实并非如此,它使用了超过1.5GB。
最大内存= [-Xmx] + [-XX:元空间大小] +线程数 * [-Xss]

**问题:**您对这一点有何看法?
应用程序概述:

此Java应用程序使用alpakka连接到pubsub并使用消息。它利用akka流的并行性,在使用的消息上执行逻辑,然后将这些消息生成到Kafka示例。请参阅下面的堆转储。注意,堆只有912.9MB,因此某些内容占用了587.1MB,内存使用量超过1.5GB

"为什么这是个问题"
此应用程序部署在kubernetes群集上,POD的内存限制指定为1.5GB。因此,当运行Java应用程序的容器占用的内存超过1.5GB时,容器将被终止并重新启动。

jc3wubiy

jc3wubiy1#

简短的回答是,这些内存并不包括JVM消耗的所有内存。
例如,在堆之外,内存分配用于:

  • 压缩类空间(由MaxMetaspaceSize控制)
  • 直接字节缓冲区(特别是如果您的应用程序执行网络I/O并关心性能,那么实际上肯定会大量使用这些缓冲区)
  • 线程(* 每个 * 线程都有一个由-Xss管理的堆栈...请注意,如果混合不同的并发模型,每个模型将倾向于分配自己的线程,而不一定提供共享线程的方法)
  • 如果涉及本机代码(例如,可能在Alpakka用于与pubsub交互的库中),则可以在堆之外分配任意数量的内存)
  • 代码缓存(通常为48 MB)
  • 垃圾收集器的状态(将根据使用的GC而变化,包括是否存在任何可调选项)
  • 其他一些通常不会那么大的

根据我的经验,使用最多(pod内存限制减去1 GB)的堆通常是相当安全的,但如果您正在执行特别大的I/O等,即使在那时也很容易发生OOM。
您的JVM可能附带了对native memory tracking的支持,这至少可以说明一些非堆消耗:大多数分配往往在应用程序完全加载后不久发生,因此以高得多的资源限制运行,然后停止(例如,通过SIGTERM,有足够的时间允许它保存结果),应该可以给予您了解正在处理的内容。

相关问题