-
Notifications
You must be signed in to change notification settings - Fork 828
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
运行长时间后内存泄露 #392
Comments
请给出最小可复现的 demo,LambdaFunction 里的 Env 只是闭包的 closure context,并不会往里面添加东西。 |
我写了个最简单的例子了: package com.googlecode.aviator.example;
import com.googlecode.aviator.AviatorEvaluator;
import com.googlecode.aviator.Expression;
public class SimpleExample {
public static void main(final String[] args) throws Exception {
Expression exp =
AviatorEvaluator.compile("let x = a > 1 && b>0 ; if(x) { return true; } else { false} ");
int i = 0;
while (true) {
exp.execute(exp.newEnv("a", i, "b", i));
i = i + 1;
}
}
} 无限循环执行, jstat 观察 gc:
可以看到内存基本没变化。 倾向于是你用法上或者缓存的实现问题。 |
抱歉忙着忘了回复。 import com.googlecode.aviator.AviatorEvaluator;
import com.googlecode.aviator.Expression;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class Test1 {
private static Expression expression = compile();
private static final ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(10, 100, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>());
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 200; ++i) {
poolExecutor.execute(() -> {
Map<String, Object> params = new HashMap<>();
params.put("$field2", new Random().nextInt());
expression.execute(params);
});
Thread.sleep(5);
}
}
private static Expression compile() {
String script = "fn func13958cf27099476b3c208d422dbfef3c() {\n" +
" let $field1 = nil;\n" +
"\n" +
" let isMatched = ($field2 >= 3);\n" +
" if(isMatched == true){\n" +
" $field1 = 'D940';\n" +
" }\n" +
"\n" +
" return seq.map('$field1', $field1, '$field2', $field2);\n" +
"}\n" +
"\n" +
"func13958cf27099476b3c208d422dbfef3c()";
return AviatorEvaluator.getInstance().compile(script, false);
}
} 涉及脚本
实际使用是Dubbo调用,所以这里用线程池去模拟Dubbo的线程池。我本地dubug断点发现最后thread pool中所有Thread所持有的threadlocalMap都没有释放,里面都是Env即请求的入参信息。 |
1 similar comment
抱歉忙着忘了回复。 import com.googlecode.aviator.AviatorEvaluator;
import com.googlecode.aviator.Expression;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class Test1 {
private static Expression expression = compile();
private static final ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(10, 100, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>());
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 200; ++i) {
poolExecutor.execute(() -> {
Map<String, Object> params = new HashMap<>();
params.put("$field2", new Random().nextInt());
expression.execute(params);
});
Thread.sleep(5);
}
}
private static Expression compile() {
String script = "fn func13958cf27099476b3c208d422dbfef3c() {\n" +
" let $field1 = nil;\n" +
"\n" +
" let isMatched = ($field2 >= 3);\n" +
" if(isMatched == true){\n" +
" $field1 = 'D940';\n" +
" }\n" +
"\n" +
" return seq.map('$field1', $field1, '$field2', $field2);\n" +
"}\n" +
"\n" +
"func13958cf27099476b3c208d422dbfef3c()";
return AviatorEvaluator.getInstance().compile(script, false);
}
} 涉及脚本
实际使用是Dubbo调用,所以这里用线程池去模拟Dubbo的线程池。我本地dubug断点发现最后thread pool中所有Thread所持有的threadlocalMap都没有释放,里面都是Env即请求的入参信息。 |
LambdaFunction 里是有 thread local 缓存,缓存 lambda 实例和上一次调用的 context,这个理论上没有影响的,每次调用都会被替换掉。用你的例子去跑,观察 gc 也是完全正常的,并不会 OOM。 |
这里唯一可能是说你传入的变量,是一个累积型的变量,由于这个 context 缓存,导致变量没有被及时 gc。 |
已经搞清楚了。 我这边配置线程池为cached,自动回收空闲线程后,这部分内存就释放了。 |
ok,收到你的建议,确实在这种情况下可能引起不必要的内存占用,我看看怎么解 |
hi. 我这边尝试clone到本地后修改源码,execute后释放这部分内存占用。 |
我用了另一个种办法解决,今天会发布 5.2.6 分支,您可以帮忙测试下 |
OK。 我check一下。 |
5.2.6 tag本地test没问题。请问今天什么时候发新release,到时候我放预生产环境试试 |
@hillfly 已发布到 oss,明天应该可以在 maven central 看到 |
使用版本:5.2.5
涉及脚本内容举例
都是简单的逻辑判断,然后返回简单的数值
编译:
Expression expression = AviatorEvaluator.getInstance().compile(scriptText, false);
localCache.put(id, expression );
....
决策:
使用方式:
系统启动时会自动加载编写好的脚本,然后编译并缓存Expression(自己实现的一套本地缓存)。
系统使用Dubbo对外提供服务,请求会把所需的入参变量传入,从本地缓存取得Expression后决策返回结果。
问题描述:
内存占用越来越大,GC也无效。
进服务器dump了后发现内存几乎被Thread吃满,然后发现是因为ThreadLocalMap中的元素无法被回收
进一步分析跟到了LambdaFunction中的Env,里面的内容看起来是每一次请求的入参信息,并没有随着请求结束而回收。
若把脚本全部改为类似下面这种不涉及高级语法的,就不会出现以上问题。
The text was updated successfully, but these errors were encountered: