Java не хватает памяти. Разве это не утечка памяти? - PullRequest
0 голосов
/ 16 марта 2020

Я назначил нашей Java программе 2 ГБ памяти. В течение часов работы определенного потока память постоянно и линейно увеличивается, пока Kubernetes не убьет ее, потому что она достигает установленного мною лимита в 2 ГБ. Конечно, мы думали об утечке памяти, но мы постоянно видим что-то подобное в журнале g c:

[7406.381s][info][gc] GC(8326) Pause Full (System.gc()) 130M->65M(214M) 157.995ms
  1. Поскольку память увеличивается линейно, в то время как эти журналы указывают, что память кучи не увеличивается, бесполезно ли исследовать утечки памяти?
  2. Что может быть другими вероятными причинами увеличения памяти?

Некоторая справочная информация:

Нет журналов, в которых говорится, что контейнер был остановлен или убит. В k8s также нет событий (однако "restarts" = 1). Приведенная выше строка журнала была последней строкой журнала, прежде чем мы увидели (в Graylog), что Spring Boot / Tomcat запускается (следовательно, он должен быть перезапущен). Мы видим, что это происходит именно в то время, когда граф памяти достигает линии 2 ГБ в Grafana. Без Графаны потребовалось бы некоторое время, прежде чем мы поняли, что это что-то связанное с памятью.

Kubernetes deploy yml part:

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

Последняя строка Dockerfile:

ENTRYPOINT ["java", "-Xmx2G", "-verbose:gc", "-jar", "/backend.jar"]

где "-verbose: g c" вызывает строки журнала, подобные приведенной выше строке.

Требуется некоторое время, чтобы воспроизвести проблему, но мы сделали это пару раз.

Мы используем Java 11.

1 Ответ

2 голосов
/ 16 марта 2020

Я не думаю, что у вас вообще есть утечка, вы просто неправильно используете опции. С -Xmx2G вы говорите Java, что он может использовать до 2G для кучи. В то же время вы говорите Kubernetes, что абсолютный предел для памяти составляет 2 Ги. Теперь Java использует память, которой нет в куче, поэтому, когда он пытается расширить кучу до 2G, он исчерпывается, и модуль уничтожается.

Чтобы устранить проблему, убедитесь, что вы разрешаете разумную поле для памяти, которая находится за пределами кучи. Временно увеличьте ограничение Kubernetes до 3G, а затем уменьшите его, когда вы знаете, сколько родной памяти вам нужно. Я предполагаю, что 2.5G - разумный уровень, но это только предположение. В качестве альтернативы вы можете уменьшить размер кучи Java и запустить с кучей 1,5 ГБ (или меньше), чтобы оставить место для собственной памяти.

...