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

Как найти коммит, в котором не было проблемы с утечкой памяти в Git

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

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

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

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

Поиск коммита без утечки памяти с помощью Git

Поиск коммита, в котором начала появляться проблема с утечкой памяти, - это важный навык при отладке регрессий. Git предоставляет несколько инструментов для эффективного поиска.

1. Git Bisect - бинарный поиск коммитов

# Инициализация bisect
git bisect start

# Указываем "плохой" коммит (с проблемой)
git bisect bad HEAD

# Указываем "хороший" коммит (без проблемы)
git bisect good v1.0.0  # или конкретный SHA-1

# Git перейдёт к коммиту посередине
# Нужно проверить, есть ли утечка памяти в этом коммите

# Если утечка есть:
git bisect bad

# Если нет:
git bisect good

# Повторяем до тех пор, пока не найдём точный коммит
git bisect reset  # Когда готово

2. Автоматизированный Git Bisect с тестом

# Создаём скрипт, который возвращает:
# 0 (good) - утечки нет
# 1 (bad) - утечка есть

#!/bin/bash
# check_memory_leak.sh
cd /path/to/project
mvn clean build  # Собираем проект

# Запускаем приложение и проверяем память
java -Xmx512m -XX:+PrintGCDetails -jar app.jar &
APP_PID=$!

# Даём приложению время запуститься
sleep 5

# Проверяем использование памяти
MEMORY=$(ps -o rss= -p $APP_PID)
KILL_PID=$APP_PID

# Если память выше порога - утечка есть
if [ $MEMORY -gt 400000 ]; then
    kill $KILL_PID
    exit 1  # bad
fi

kill $KILL_PID
exit 0  # good

# Использование в bisect:
git bisect start
git bisect bad HEAD
git bisect good v1.0.0
git bisect run ./check_memory_leak.sh  # Автоматический поиск

3. Git Log с анализом истории

# Просмотр истории изменений файла, содержащего утечку
git log -p --follow -- src/main/java/com/example/MemoryLeaky.java

# Просмотр изменений в конкретный период времени
git log --since="2024-01-01" --until="2024-02-01" --oneline

# Просмотр коммитов, изменивших конкретную функцию
git log -L:methodName:src/main/java/MyClass.java

# Поиск по сообщению коммита
git log --grep="memory" --grep="leak" --oneline

# Комбинированный поиск
git log --all --source --oneline --since="3 months ago" -- \
    src/main/java/com/example/ResourceManager.java

4. Git Blame для выявления ответственного

# Показывает, кто и когда внёс изменения в каждую строку
git blame src/main/java/com/example/ResourcePool.java

# Вывод содержит:
# <commit> <author> <date> <line_number> <code>

# Более подробно
git blame -L 100,150 src/main/java/com/example/ResourcePool.java

# С информацией о коммите
git blame -L 100,150 -c src/main/java/com/example/ResourcePool.java

5. Программный подход с Java тестом

// MemoryLeakTest.java
import java.lang.management.*;
import java.util.*;

public class MemoryLeakTest {
    @Test
    public void detectMemoryLeak() throws Exception {
        MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean();
        
        // Начальное состояние памяти
        MemoryUsage initial = memoryBean.getHeapMemoryUsage();
        long initialUsed = initial.getUsed();
        
        // Создание нескольких объектов
        simulateApplicationLoad(10000);
        
        // Принудительная сборка мусора
        System.gc();
        Thread.sleep(1000);
        
        // Проверка памяти после GC
        MemoryUsage after = memoryBean.getHeapMemoryUsage();
        long afterUsed = after.getUsed();
        
        long difference = afterUsed - initialUsed;
        
        // Если память увеличилась более чем на пороговое значение
        assertTrue(
            difference < 10_000_000, // 10 MB
            "Memory leak detected! Difference: " + difference
        );
    }
    
    private void simulateApplicationLoad(int iterations) {
        for (int i = 0; i < iterations; i++) {
            // Код приложения
        }
    }
}

6. Практический пример Git Bisect

# Сценарий: утечка памяти появилась между v1.5.0 и HEAD

# Шаг 1: Начинаем bisect
$ git bisect start
$ git bisect bad HEAD
$ git bisect good v1.5.0
Bisecting: 45 revisions left to test after this
# Переходит к коммиту посередине

# Шаг 2: Проверяем память в этом коммите
$ mvn clean install
$ java -jar target/app.jar
# Профилируем или проверяем память
# Видим, что утечка есть

# Шаг 3: Указываем, что это плохой коммит
$ git bisect bad
Bisecting: 22 revisions left to test after this

# Шаг 4: Повторяем процесс
$ mvn clean install
$ java -jar target/app.jar
# Утечки нет

$ git bisect good
Bisecting: 11 revisions left to test after this

# ... (повторяем несколько раз)

# Финально:
commit a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p
Author: John Doe <john@example.com>
Date:   Mon Jan 15 10:30:45 2024

    Fix improper resource cleanup in ConnectionPool

This is the first bad commit
$ git bisect reset

7. JFR (Java Flight Recorder) для анализа

# Запуск приложения с JFR
java -XX:+UnlockCommercialFeatures \
     -XX:+FlightRecorder \
     -XX:StartFlightRecording=duration=60s,filename=leak.jfr \
     -jar app.jar

# Анализ в JMC (Java Mission Control)
jmc leak.jfr

# Или через jcmd
jcmd <pid> JFR.start duration=60s filename=output.jfr
jcmd <pid> JFR.dump filename=output.jfr
jcmd <pid> JFR.stop

8. Визуальный анализ в IDE

# Git History в IDE (IntelliJ IDEA, VS Code)
1. Открыть файл с проблемой
2. Меню: Git → Show History
3. Просмотреть все изменения в файле
4. Выбрать подозрительный коммит
5. Просмотреть diff

# Или использовать:
# Right-click на файл → Git → Show History

9. Скрипт для полного анализа

#!/bin/bash
# find_memory_leak.sh

echo "Запуск поиска утечки памяти..."

BAD_COMMIT=$(git rev-parse HEAD)
GOOD_COMMIT=$1

if [ -z "$GOOD_COMMIT" ]; then
    echo "Использование: $0 <good_commit>"
    exit 1
fi

echo "Bad commit: $BAD_COMMIT"
echo "Good commit: $GOOD_COMMIT"

git bisect start
git bisect bad $BAD_COMMIT
git bisect good $GOOD_COMMIT

while true; do
    echo "Building project..."
    mvn clean install -q
    
    echo "Testing for memory leak..."
    if timeout 30 java -Xmx512m -jar target/app.jar > /dev/null 2>&1; then
        echo "No leak detected - marking as good"
        git bisect good
    else
        echo "Leak detected - marking as bad"
        git bisect bad
    fi
    
    # Проверяем, завершился ли bisect
    if [ $? -ne 0 ]; then
        git bisect reset
        break
    fi
done

echo "Done!"

Лучшие практики

  1. Регулярно тестируй память - используй JMeter или LoadRunner
  2. Отслеживай метрики - heap size, GC time в мониторинге
  3. Проверяй профилировщиком - YourKit, JProfiler перед merging
  4. Unit-тесты на утечки - используй @After для проверки ресурсов
  5. Code review - обращай внимание на управление ресурсами

Вывод: Git Bisect - самый эффективный способ найти коммит с регрессией. Для утечек памяти лучше комбинировать с автоматическими тестами.

Как найти коммит, в котором не было проблемы с утечкой памяти в Git | PrepBro