Поймать последний процесс перед ошибкой нехватки памяти - PullRequest
0 голосов
/ 21 января 2020

У меня есть система, в которой JVM работает как windows, в которой запущено 4 процесса. JVM настроен на автоматический перезапуск при возникновении ошибки.

Недавно я столкнулся с этой проблемой, когда JVM прекращает выполнение одного из процессов и просто загружает процессор (90 +%), но в журналах исключений не обнаружено. Однако примерно через 30 минут он показал ошибку нехватки памяти и затем перезапустил.

Я использовал -XX: + HeapDumpOnOutOfMemoryError, чтобы сгенерировать файл hprof, который я открыл в Eclipse MAT, но я делаю не понимаю, как отследить его до моего кода.

Мои вопросы:

  1. Можно ли сгенерировать OOME, когда JVM зависает вместо ожидания Stacktrace распечатать ошибку?

  2. Есть ли способ отловить последний запущенный процесс перед зависанием? Или способ выяснить, какой процесс может иметь утечку.

Большое спасибо!

1 Ответ

0 голосов
/ 21 января 2020

Да, если вы сделаете поле MEGABYTES достаточно большим в этом примере, вы можете заставить свою JVM выдавать ошибку OutOfMemoryError и выводить трассировку стека:

public class MemoryTest {
    public static void main(String[] args) {
        final int MEGABYTES = 1000;
        memoryTest(MEGABYTES);
    }
    public static void memoryTest(int megabytes){
        showMemory("Begin");
        try {
            useMemory(megabytes);
        } catch(OutOfMemoryError e){
            System.out.println("About to run out of memory!");
            // also dump the stack trace
            e.printStackTrace();
        }

        System.gc();
        showMemory("After GC");
    }
    static void useMemory(int megaBytes){
        final int MB = 1024*512;
        byte[][] bytes = new byte[megaBytes][];
        for(var c=0;c<megaBytes;c++){
            bytes[c] = new byte[MB];
        }
        showMemory("After useMemory");
    }
    static void showMemory(String heading){
        long allocated = Runtime.getRuntime().totalMemory()/(1024*1024);
        long used = ((Runtime.getRuntime().totalMemory()-Runtime.getRuntime().freeMemory())/(1024*1024));
        long max = (Runtime.getRuntime().maxMemory()/(1024*1024));
        long available = max - used;

        System.out.println(heading);
        System.out.println("\tVM Allocated Memory is: " + allocated +"MB");
        System.out.println("\tUsed Memory is: " + used +"MB");
        System.out.println("\tAvailable Memory is: " + available +"MB");
    }

}
...