Проблема : приложение закрыто из-за использования памяти
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 показывает постоянный рост памяти (очень маленькими порциями):
Интересное исследование : во время бесконечного тестирования я обнаружилследующее: когда я установил xmx = 134MB, приложение дольше работает и было способно выдержать 5 раундов тестов производительности, когда я установил xmx / xms = 200mb, оно выдержало 1 раунд тестов производительности. Как это могло быть возможно?
Мое мнение : Похоже, что что-то использует память и не освобождает ее должным образом.
Мне бы хотелось услышать вашемнения относительно того, почему мое приложение постоянно умирает, когда имеется более 50 МБ свободной памяти, и почему показатели AWS показывают другой результат по сравнению с инструментами Java