Java 内存不足。这不是内存泄漏吗?

Alb*_*iks 1 java memory-leaks docker grafana kubernetes

我为我们的 Java 程序分配了 2GB 内存。在特定线程运行的时间内,内存会稳定且线性地增加,直到 Kubernetes 将其杀死,因为它达到了我分配的 2GB 限制。当然,我们正在考虑内存泄漏,但我们总是在 gc 日志中看到这样的内容:

[7406.381s][info][gc] GC(8326) Pause Full (System.gc()) 130M->65M(214M) 157.995ms
Run Code Online (Sandbox Code Playgroud)
  1. 既然内存线性增加,而这些日志表明堆内存没有增加,那么调查内存泄漏就没用了吗?
  2. 记忆力增加的其他可能原因是什么?

一些背景信息:

没有日志表明容器已被停止或终止。k8s 中也没有事件(但是“重新启动”= 1)。上面的日志行是我们(在 Graylog 中)看到 Spring Boot / Tomcat 正在启动之前的最后一个日志行(因此它必须已重新启动)。我们看到这种情况恰好发生在 Grafana 中内存图达到 2GB 线时。如果没有 Grafana,我们可能需要一段时间才能弄清楚这是与内存相关的东西。

Kubernetes部署yml部分:

spec:
  template:
    spec:
      containers:
        - name: ... (omitted)
          resources:
            limits:
              cpu: 1200m
              memory: 2Gi
            requests:
              cpu: 50m
              memory: 50Mi
Run Code Online (Sandbox Code Playgroud)

Dockerfile 的最后一行:

ENTRYPOINT ["java", "-Xmx2G", "-verbose:gc", "-jar", "/backend.jar"]
Run Code Online (Sandbox Code Playgroud)

其中“-verbose:gc”导致日志行类似于我上面引用的行。

重现该问题需要一段时间,但我们已经这样做了几次。

我们正在使用 Java 11。

ewr*_*ner 5

我认为你根本没有泄漏,你只是使用了错误的选项。你告诉-Xmx2GJava 它最多可以使用 2G 的堆空间。同时你告诉 Kubernetes 内存的绝对限制是 2Gi。现在,Java 使用不在堆上的内存,因此当它尝试将堆扩展到 2G 时,它会耗尽并且 pod 会被终止。

要解决此问题,请确保为堆外的内存留出合理的余量。暂时将 Kubernetes 限制增加到 3G,然后在知道需要多少本机内存后将其缩小。我猜测 2.5G 是一个合理的水平,但这只是一个猜测。或者,您可以减小 Java 堆大小并使用 1.5G 堆(或更少)运行,为本机内存留出一些空间。