我有一个 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 工具获取一些信息,我知道这是一个堆外问题。但我无法将它与代码连接,所以我找不到我的代码的哪一行不正确。