← Назад к вопросам

Как определить, сколько памяти потребляет Java-приложение, упакованное в *.jar, при запуске через команду java-jar, если оно завершается с ошибкой "No heap space"?

2.0 Middle🔥 151 комментариев
#Другое

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

# Диагностика потребления памяти Java приложения при ошибке "No heap space"

Ошибка "java.lang.OutOfMemoryError: Java heap space" означает, что приложение исчерпало отведённую кучу. Нужно определить текущее потребление и настроить параметры запуска.

Способ 1: Установка явных лимитов памяти и мониторинг

Базовое увеличение памяти

# Минимальный вариант
java -jar application.jar

# С явными параметрами памяти
java -Xms512m -Xmx2g -jar application.jar
# -Xms512m = начальный размер heap = 512 МБ
# -Xmx2g = максимальный размер heap = 2 ГБ

# Рекомендуемые значения
java -Xms1g -Xmx4g -jar application.jar

# Для больших приложений
java -Xms4g -Xmx8g -XX:+UseG1GC -jar application.jar

Способ 2: Включение GC логирования для анализа

# Java 8
java -Xms1g -Xmx4g \
  -XX:+PrintGCDetails \
  -XX:+PrintGCDateStamps \
  -Xloggc:gc.log \
  -jar application.jar

# Java 9+
java -Xms1g -Xmx4g \
  -Xlog:gc*:file=gc.log:time,uptime,level,tags \
  -jar application.jar

Анализируем gc.log:

2024-03-22T10:15:30.123+0000: 5.432: [GC (Allocation Failure) [PSYoungGen: 262144K->32768K(262144K)] 262144K->65536K(1048576K), 0.0245031 secs]
                              ↑                                                        ↑
                           Время GC                                              Общее потребление

Способ 3: Создание и анализ heap dump

Способ 3a: Запуск с автоматическим dump при OOM

java -Xms1g -Xmx4g \
  -XX:+HeapDumpOnOutOfMemoryError \
  -XX:HeapDumpPath=./heap-dump.hprof \
  -jar application.jar

# При ошибке OOM автоматически создается файл heap-dump.hprof

Способ 3b: Ручное создание dump текущего приложения

# 1. Получаем PID приложения
jps -l
# Output: 12345 /path/to/application.jar

# 2. Создаём dump в режиме реального времени
jmap -dump:live,format=b,file=heap-dump.hprof 12345

# 3. Анализируем dump с помощью Eclipse Memory Analyzer
# или jhat (встроенный инструмент)
jhat heap-dump.hprof
# Откроется веб-интерфейс на http://localhost:7000

Способ 4: Мониторинг в реальном времени с JMX

Включаем JMX при запуске

java -Xms1g -Xmx4g \
  -Dcom.sun.management.jmxremote \
  -Dcom.sun.management.jmxremote.port=9010 \
  -Dcom.sun.management.jmxremote.authenticate=false \
  -Dcom.sun.management.jmxremote.ssl=false \
  -Djava.rmi.server.hostname=localhost \
  -jar application.jar

Подключаемся через JConsole или VisualVM

# JConsole (встроенный)
jconsole
# затем выбираем процесс из списка и монитор Memory

# VisualVM (мощнее)
jvisualvm
# File → Add JMX Connection → localhost:9010

Способ 5: Использование команды jstat для статистики

# Получаем PID
jps -l

# Смотрим статистику GC каждую секунду
jstat -gc 12345 1000
# Output:
#  S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU    CCSC   CCSU
# 2048.0 2048.0 0.0    2048.0 16384.0 12288.0   20480.0   15360.0   24576.0 23552.0 0.0    0.0
#
# S0C/S1C = Young generation survivor space
# EC = Eden space
# OC = Old generation capacity
# OU = Old generation used

# Более подробная статистика
jstat -gcutil 12345 1000
# Output (проценты):
#  S0     S1     E      O      M     CCS    YGC     YGCT    FGC    FGCT     GCT
# 0.00  100.00 50.00  75.00  96.00  0.00  12      1.234   2      0.456   1.690

Способ 6: Анализ размера объектов в коде

// Если нужно понять потребление памяти программно
public class MemoryAnalyzer {
    public static void main(String[] args) {
        Runtime runtime = Runtime.getRuntime();
        
        // Общая память, выделенная для JVM
        long totalMemory = runtime.totalMemory();
        
        // Свободная память
        long freeMemory = runtime.freeMemory();
        
        // Использованная память
        long usedMemory = totalMemory - freeMemory;
        
        // Максимальная доступная память
        long maxMemory = runtime.maxMemory();
        
        System.out.println("=== Memory Stats ===");
        System.out.println("Total Memory: " + formatBytes(totalMemory));
        System.out.println("Used Memory: " + formatBytes(usedMemory));
        System.out.println("Free Memory: " + formatBytes(freeMemory));
        System.out.println("Max Memory: " + formatBytes(maxMemory));
        System.out.println("Available for use: " + formatBytes(maxMemory - usedMemory));
    }
    
    private static String formatBytes(long bytes) {
        if (bytes <= 0) return "0 B";
        final String[] units = new String[] { "B", "KB", "MB", "GB" };
        int digitGroups = (int) (Math.log10(bytes) / Math.log10(1024));
        return String.format("%.2f %s", bytes / Math.pow(1024, digitGroups), 
                           units[digitGroups]);
    }
}

Способ 7: Встроенные флаги для диагностики

# Показать настройки памяти при запуске
java -XX:+PrintFlagsFinal -jar application.jar | grep HeapSize
# Output:
# long InitialHeapSize = 268435456 (256 MB)
# long MaxHeapSize = 4294967296 (4 GB)

# Печать информации о GC при каждом сборке
java -Xms1g -Xmx4g \
  -XX:+UnlockDiagnosticVMOptions \
  -XX:+TraceClassLoading \
  -jar application.jar

# Рекомендуемые настройки для production
java -Xms2g -Xmx4g \
  -XX:+UseG1GC \
  -XX:MaxGCPauseMillis=200 \
  -XX:+ParallelRefProcEnabled \
  -XX:+AlwaysPreTouch \
  -Xlog:gc*:file=gc.log:time,uptime,level,tags \
  -jar application.jar

Практический пример полной диагностики

#!/bin/bash
# debug-memory.sh

APP_JAR="application.jar"
HEAP_DUMP_FILE="heap-dump-$(date +%s).hprof"
GC_LOG="gc-$(date +%s).log"

echo "Starting application with memory monitoring..."
echo "Heap dump will be saved to: $HEAP_DUMP_FILE"
echo "GC log will be saved to: $GC_LOG"

java \
  -Xms512m \
  -Xmx2g \
  -XX:+UseG1GC \
  -XX:+HeapDumpOnOutOfMemoryError \
  -XX:HeapDumpPath="$HEAP_DUMP_FILE" \
  -Xlog:gc*:file="$GC_LOG":time,uptime,level,tags \
  -Dcom.sun.management.jmxremote \
  -Dcom.sun.management.jmxremote.port=9010 \
  -Dcom.sun.management.jmxremote.authenticate=false \
  -Dcom.sun.management.jmxremote.ssl=false \
  -Djava.rmi.server.hostname=localhost \
  -jar "$APP_JAR"

echo "Application finished. Check $HEAP_DUMP_FILE and $GC_LOG"

Рекомендации для решения проблемы

Шаг 1: Определи реальное потребление

# Запусти с увеличенной памятью и мониторь
java -Xms1g -Xmx4g -Xlog:gc*:file=gc.log -jar app.jar

# Проверь gc.log — найди максимальный размер heap перед OOM

Шаг 2: Если OOM вызывает утечка памяти

# Создай heap dump при ошибке
java -Xmx4g \
  -XX:+HeapDumpOnOutOfMemoryError \
  -XX:HeapDumpPath=./dump.hprof \
  -jar app.jar

# Затем анализируй dump в Eclipse MAT (Memory Analyzer Tool)
# Ищи retained objects с большим размером

Шаг 3: Оптимизируй

  • Уменьшай размеры коллекций
  • Освобождай неиспользуемые объекты
  • Используй более эффективные структуры данных
  • Включи G1GC для больших heap: -XX:+UseG1GC

Таблица параметров для разных сценариев

СценарийПараметры
Микросервис-Xms512m -Xmx1g -XX:+UseG1GC
Веб-приложение-Xms1g -Xmx4g -XX:+UseG1GC -XX:MaxGCPauseMillis=200
Обработка больших данных-Xms4g -Xmx16g -XX:+UseG1GC -XX:MaxGCPauseMillis=500
Production система-Xms2g -Xmx8g -XX:+UseG1GC -XX:+ParallelRefProcEnabled -XX:+AlwaysPreTouch

Диагностику памяти начинай с включения GC логирования и heap dump при OOM. Это даст 80% информации для решения проблемы.

Как определить, сколько памяти потребляет Java-приложение, упакованное в *.jar, при запуске через команду java-jar, если оно завершается с ошибкой "No heap space"? | PrepBro