Бывает надо заглянуть внутрь JVM.
Увидеть CPU, ядра, потоки, а чаще heapMemory - но у тебя ничего для этого нет.
Ни Prometheus, ни других систем мониторинга. Ещё не настроено окружение.

Бэкендер без мониторинга
Бэкендер без мониторинга

Как можно проверить JVM на коленке?

Есть относительно простой способ сделать это в любых условиях.
На localhost.
На стенде разработки.
На продуктовом стенде (но тут на свой страх и риск - обязательно закрывайте авторизацией).

И здесь мне однажды помог...Custom endpoint, который отдаёт снимок состояния Java Platform MXBeans.


MXBeans

Если начать читать про MXBeans - вы скорее всего начитаете, что эта технология отходит на второй план. Когда оно было на пике популярности, я вообще ещё не разрабатывал приложения.
Да, всё меняется. Это и правда устарело, в эпоху систем мониторинга.

Но допустим, в нашем кейсе мониторинга нет.
И настраивать затратно. Поэтому продолжаем.

Platform MXBeans (Managed Beans) - это встроенные в Java виртуальную машину стандартные интерфейсы (JMX-компоненты) для управления и мониторинга работы JVM и операционной системы.

По сути это специальные объекты.
По дефолту JVM поднимает эти объекты сама при старте приложения.
Достать их можно через статические методы класса ManagementFactory.
Их много разных, у каждого свой небольшой кусочек ответственности.

  • MemoryMXBean - мониторит состояние Heap и Non-Heap памяти, считает загрузку памяти.

  • OperatingSystemMXBean - позволяет заглянуть за пределы JVM и узнать загрузку процессора хоста (CPU), количество ядер и свободную физическую память котнейнера.

  • ThreadMXBean - считает количество живых потоков, пиковое значение потоков, а также умеет находить взаимные блокировки.

  • GarbageCollectorMXBean - отдаёт статистику по сборщикам мусора: сколько раз запускались и сколько миллисекунд заняли паузы (Stop-the-world).


Связь с VisualVM, Prometheus

Почти каждый слышал про VisualVM - древний, но крутой софт для просмотра состояния JVM.

Любопытный факт №1
Когда вы подключаете VisualVM к Java процессу - он сразу же строит графики.
Информацию с Java процесса он собирает как раз благодаря заранее настроенным MXBeans.

Любопытный факт №2
Есть способ экспорта этих же метрик MXBean из Java-приложения в формат Prometheus. Стандартом для этого является использование утилиты Prometheus JMX Exporter


Если связать всё вместе

Частично, вы можете увидеть то что показывается в VisualVM, но без VisualVM.
Для этого надо ручками написать Endpoint, код которого опрашивает MXBeans и отправляет статус приложения в ответе. Ничего сверхъестественного, но думаю это стоит упомянуть, потому что:

  1. Для этого не нужны дополнительные библиотеки.

  2. Не нужно специфичное окружение - независимо от среды это запустится

Вот пример Endpoint-а, который собирает полезную информацию о JVM

import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
import java.lang.management.ManagementFactory

@RestController
@RequestMapping("/internal/diagnostics")
class JvmDiagnosticsController {

    @GetMapping("/snapshot")
    fun getJvmSnapshot(): Map<String, Any> {
        val memory = ManagementFactory.getMemoryMXBean()
        val threads = ManagementFactory.getThreadMXBean()
        val os = ManagementFactory.getOperatingSystemMXBean()

        return mapOf(
            "timestamp" to System.currentTimeMillis(),
            "memory" to mapOf(
                "heap_used_mb" to memory.heapMemoryUsage.used / 1024 / 1024,
                "heap_max_mb" to memory.heapMemoryUsage.max / 1024 / 1024,
                "non_heap_used_mb" to memory.nonHeapMemoryUsage.used / 1024 / 1024
            ),
            "threads" to mapOf(
                "live" to threads.threadCount,
                "peak" to threads.peakThreadCount,
                "deadlocked_count" to (threads.findDeadlockedThreads()?.size ?: 0)
            ),
            "system" to mapOf(
                "cpu_load_pct" to (os.systemLoadAverage * 100).toInt(),
                "available_processors" to os.availableProcessors
            )
        )
    }
}

P.S.

Не надо использовать способ с Endpoint-ом как основу.
Лучше используйте что-то современное.
Prometheus, Micrometer, Spring Actuator.
Но если ничего нет - есть вот такая палочка-выручалочка.