Почему и как узнать, где происходят утечки памяти вне кучи JVM

У меня есть проект Java, который показывает утечку памяти в среде продукта. Мы можем видеть, как его память расширяется и становится все больше и больше, используя 'top' или 'cat /proc/PID/status|grep VmRSS', но его куча JVM остается в хорошем состоянии, что означает, что память кучи находится под контролем '-Xmx'и другие варианты JVM. Я использовал jmap/dump/jstack и любая другая команда, которую я знаю, чтобы проанализировать, что не так, но напрасно.

Наконец, мы обнаружили проблему, построчно тестируя. Это проблема в движке JVM JavaScript. Я извлек здесь код, который может воспроизвести проблему:

package com.unionpay.cqp.arch.js;


import javax.script.*;


import static java.lang.Thread.sleep;


public class JsEngineMain {
    private static final ScriptEngine SCRIPT_ENGINE = new ScriptEngineManager().getEngineByName("JavaScript");
    private static final String SCRIPT_FUNC_1 = "function max_num(a, b){return (a>b)?a:b;} ";


    public static void main(String[] args) {
        if (args == null || args.length < 1) {
            System.out.println("wrong args, use like:");
            System.out.println("java -jar xxx.jar SLEEP_TIME_MILLIES");
            System.out.println("java -cp xxx.jar com.unionpay.cqp.arch.js.JsEngineMainBak SLEEP_TIME_MILLIES");
            return;
        }
        long sleepTime = Long.parseLong(args[0]);
        try {
            while (true) {
                sleep(sleepTime);
                testLoopFuncString();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    private static void testLoopFuncString() {
        try {
            Compilable compilable = (Compilable) SCRIPT_ENGINE;
            CompiledScript compiledScript = compilable.compile(SCRIPT_FUNC_1);
            compiledScript.eval();
            Invocable invocable = (Invocable) SCRIPT_ENGINE;
            Object res = invocable.invokeFunction("max_num", 6, 1);
            showRes(res);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    private static void showRes(Object res) {
        if (System.currentTimeMillis() % 20000 == 1) {
            System.out.println(res);
        }
    }
}

Вы можете запустить его с помощью команды:

java -Xmx 128M -XX:MaxMetaspaceSize=64M -XX:MaxDirectMemorySize=64M -cp js-engine-test.jar com.unionpay.cqp.arch.js.JsEngineMain 2

и отслеживать использование памяти с помощью:

while true; do cat /proc/PID/status|grep VmRSS;sleep 5;done

Тогда вы увидите, что использование памяти со временем растет.

Ну, у меня вопрос, как найти проблему, если мы не знаем, в чем проблема? И как найти неверный код с помощью анализа памяти или командных инструментов?

я использую pmap и jcmdЧтобы увидеть, где занята память, я могу получить некоторую информацию из инструментов jcmd, и я знаю, что это проблема вне кучи. но я не могу связать это с кодами, поэтому я не могу найти, какая строка моего кода неверна.

0 ответов

Другие вопросы по тегам