Почему Java приложение Docker убивается из-за памяти? - PullRequest
0 голосов
/ 28 октября 2019

Проблема : приложение закрыто из-за использования памяти

  Status reason OutOfMemoryError: Container killed due to memory usage
  Exit Code 137

Среда : приложение Spring Boot в док-контейнере на экземпляре AWS ECS с конфигурацией:

  • Предел жесткой памяти AWS / общий объем ОЗУ - 384 МБ
  • -Xmx134m
  • -Xms134m
  • -XX: MaxMetaspaceSize = 110 м

Согласно формуле java max memory (которую я нашел за несколько недель исследований - https://dzone.com/articles/why-does-my-java-process и немного улучшил):

max_memory = xmx + non-heap_memory + threads_number * xss

non-heap_memory = metaspace + (сжатый_класс_space + codeHeap_profiledmethods + CodeHeap_non-method + CodeHeap_non-profiled_methods

1032 *1032* 1032 *1032* 1032 *1032* 1032 *1032* 1032 *1032* 1032 *1032* 1032 *1032* 1032 *1032* 1032 *1032* 1032 *1032* 1032 *1032* 1032 *1032* 1032 *1032* 1032 *1032* 1032 *1032* 1032 *1032* 1032 *1032* 1032 *1032* 1032 *1032* 1032 *1032* 1032 *1032* 1032 *1032* 1032Учтите, что 2-я часть памяти без кучи занимает почти 40 МБ в совокупности

, поэтому в моем случае max_memory = 134(xmx) + 110(metaspace_max) + 40(non-heap-not_metaspace) + 9(threads) * 1(default Xss) = 293

Однако при загрузке heapUsedMemory = ~ 105-120 МБ и non-heapUsedMemory (metaspace + JVM материал) = ~ 140 МБ, что означает, чтобыть 384 - 120 - 140 = 124 МБ свободной памяти . Таким образом, проблема в том, что есть много свободной памяти, и все инструменты Java показывают это (jstat -gc, Spring on grafana, различные API Java и т. Д.). Вот фрагмент кода API, который я разработал и использовал во время моего исследования:

    @GetMapping("/memory/info")
public Map<String, String> getMmUsage() {
    Map<String, Long> info = new HashMap<>();
    List<MemoryPoolMXBean> memPool = ManagementFactory.getMemoryPoolMXBeans();
    for (MemoryPoolMXBean p : memPool) {
        if ("Metaspace".equals(p.getName())) {
            info.put("metaspaceMax", p.getUsage().getMax());
            info.put("metaspaceCommitted", p.getUsage().getCommitted());
            info.put("metaspaceUsed", p.getUsage().getUsed());
        }
    }

    info.put("heapMax", ManagementFactory.getMemoryMXBean().getHeapMemoryUsage().getMax());
    info.put("heapCommitted", ManagementFactory.getMemoryMXBean().getHeapMemoryUsage().getCommitted());
    info.put("heapUsed", ManagementFactory.getMemoryMXBean().getHeapMemoryUsage().getUsed());
    info.put("non-heapMax", ManagementFactory.getMemoryMXBean().getNonHeapMemoryUsage().getMax());
    info.put("non-heapCommitted", ManagementFactory.getMemoryMXBean().getNonHeapMemoryUsage().getCommitted());
    info.put("non-heapUsed", ManagementFactory.getMemoryMXBean().getNonHeapMemoryUsage().getUsed());

    Map<String, String> memoryData = info.entrySet().stream().collect(Collectors.toMap(Entry::getKey, e -> {
        long kb = e.getValue() / 1024;
        return (kb / 1024) + " Mb (" + kb + " Kb)";
    }, (v1, v2) -> v1, TreeMap::new));

    Set<Thread> threads = Thread.getAllStackTraces().keySet();
    memoryData.put("threadsCount", Integer.toString(threads.size()));
    memoryData.put("threadsCountRunning",
            Long.toString(threads.stream().filter(t -> t.getState() == Thread.State.RUNNABLE).count()));

    return memoryData;
}

Таким образом, мое приложение должно быть стабильным, так как имеет много памяти для работы. Но это не так. Как я описал выше Container killed due to memory usage

Как я описал выше, инструменты Java показывают, что имеется много памяти и что память (куча) освобождается. С другой стороны, метрика AWS cloudwatch MmeoryUtilization показывает постоянный рост памяти (очень маленькими порциями): aws cloudwatch metric

Интересное исследование : во время бесконечного тестирования я обнаружилследующее: когда я установил xmx = 134MB, приложение дольше работает и было способно выдержать 5 раундов тестов производительности, когда я установил xmx / xms = 200mb, оно выдержало 1 раунд тестов производительности. Как это могло быть возможно?

Мое мнение : Похоже, что что-то использует память и не освобождает ее должным образом.

Мне бы хотелось услышать вашемнения относительно того, почему мое приложение постоянно умирает, когда имеется более 50 МБ свободной памяти, и почему показатели AWS показывают другой результат по сравнению с инструментами Java

...