Skip to content

Commit e335bf1

Browse files
committed
Fixed memory leak when doesn't using cache.
1 parent 0ca4218 commit e335bf1

File tree

3 files changed

+80
-42
lines changed

3 files changed

+80
-42
lines changed

src/main/java/com/googlecode/aviator/AviatorEvaluator.java

Lines changed: 56 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -82,14 +82,15 @@
8282

8383
/**
8484
* Avaitor Expression evaluator
85-
*
85+
*
8686
* @author dennis
87-
*
87+
*
8888
*/
8989
public final class AviatorEvaluator {
9090
private static Boolean trace = Boolean.valueOf(System.getProperty("aviator.asm.trace", "false"));
9191

9292
// The classloader to define generated class
93+
@Deprecated
9394
private static AviatorClassLoader aviatorClassLoader;
9495

9596
/**
@@ -125,7 +126,7 @@ public final class AviatorEvaluator {
125126

126127
/**
127128
* Configure whether to trace code generation
128-
*
129+
*
129130
* @param t
130131
* true is to trace,default is false.
131132
*/
@@ -136,7 +137,7 @@ public static void setTrace(boolean t) {
136137

137138
/**
138139
* Get current trace output stream,default is System.out
139-
*
140+
*
140141
* @return
141142
*/
142143
public static OutputStream getTraceOutputStream() {
@@ -146,7 +147,7 @@ public static OutputStream getTraceOutputStream() {
146147

147148
/**
148149
* Returns current math context for decimal.
149-
*
150+
*
150151
* @since 2.3.0
151152
* @return
152153
*/
@@ -157,7 +158,7 @@ public static MathContext getMathContext() {
157158

158159
/**
159160
* Set math context for decimal.
160-
*
161+
*
161162
* @param mathContext
162163
* @since 2.3.0
163164
*/
@@ -171,7 +172,7 @@ public static void setMathContext(MathContext mathContext) {
171172

172173
/**
173174
* Set trace output stream
174-
*
175+
*
175176
* @param traceOutputStream
176177
*/
177178
public static void setTraceOutputStream(OutputStream traceOutputStream) {
@@ -257,19 +258,19 @@ public AviatorClassLoader run() {
257258
* Compiled Expression cache
258259
*/
259260
private final static ConcurrentHashMap<String/* text expression */, FutureTask<Expression>/*
260-
* Compiled
261-
* expression
262-
* task
263-
*/> cacheExpressions =
264-
new ConcurrentHashMap<String, FutureTask<Expression>>();
261+
* Compiled
262+
* expression
263+
* task
264+
*/> cacheExpressions =
265+
new ConcurrentHashMap<String, FutureTask<Expression>>();
265266

266267

267268
/**
268269
* set optimize level,default AviatorEvaluator.EVAL
269-
*
270+
*
270271
* @see #COMPILE
271272
* @see #EVAL
272-
*
273+
*
273274
* @param value
274275
*/
275276
public static void setOptimize(int value) {
@@ -300,17 +301,30 @@ public static void clearExpressionCache() {
300301

301302
/**
302303
* Returns classloader
303-
*
304+
*
304305
* @return
305306
*/
306307
public static AviatorClassLoader getAviatorClassLoader() {
307-
return aviatorClassLoader;
308+
return getAviatorClassLoader(false);
309+
}
310+
311+
312+
/**
313+
* Returns classloader
314+
*
315+
* @return
316+
*/
317+
public static AviatorClassLoader getAviatorClassLoader(boolean cached) {
318+
if (cached)
319+
return aviatorClassLoader;
320+
else
321+
return new AviatorClassLoader(Thread.currentThread().getContextClassLoader());
308322
}
309323

310324

311325
/**
312326
* Add a aviator function
313-
*
327+
*
314328
* @param function
315329
*/
316330
public static void addFunction(AviatorFunction function) {
@@ -321,7 +335,7 @@ public static void addFunction(AviatorFunction function) {
321335

322336
/**
323337
* Remove a aviator function by name
324-
*
338+
*
325339
* @param name
326340
* @return
327341
*/
@@ -332,7 +346,7 @@ public static AviatorFunction removeFunction(String name) {
332346

333347
/**
334348
* get a aviator function by name,throw exception if null
335-
*
349+
*
336350
* @param name
337351
* @return
338352
*/
@@ -347,7 +361,7 @@ public static AviatorFunction getFunction(String name) {
347361

348362
/**
349363
* Check if the function is existed in aviator
350-
*
364+
*
351365
* @param name
352366
* @return
353367
*/
@@ -358,7 +372,7 @@ public static boolean containsFunction(String name) {
358372

359373
/**
360374
* Remove a aviator function
361-
*
375+
*
362376
* @param function
363377
* @return
364378
*/
@@ -369,17 +383,18 @@ public static AviatorFunction removeFunction(AviatorFunction function) {
369383

370384
/**
371385
* Configure user defined classloader
372-
*
386+
*
387+
* @deprecated
373388
* @param aviatorClassLoader
374389
*/
375390
public static void setAviatorClassLoader(AviatorClassLoader aviatorClassLoader) {
376-
AviatorEvaluator.aviatorClassLoader = aviatorClassLoader;
391+
// AviatorEvaluator.aviatorClassLoader = aviatorClassLoader;
377392
}
378393

379394

380395
/**
381396
* Returns a compiled expression in cache
382-
*
397+
*
383398
* @param expression
384399
* @return
385400
*/
@@ -396,14 +411,14 @@ public static Expression getCachedExpression(String expression) {
396411

397412
/**
398413
* Compile a text expression to Expression object
399-
*
414+
*
400415
* @param expression
401416
* text expression
402417
* @param cached
403418
* Whether to cache the compiled result,make true to cache it.
404419
* @return
405420
*/
406-
public static Expression compile(final String expression, boolean cached) {
421+
public static Expression compile(final String expression, final boolean cached) {
407422
if (expression == null || expression.trim().length() == 0) {
408423
throw new CompileExpressionErrorException("Blank expression");
409424
}
@@ -416,7 +431,7 @@ public static Expression compile(final String expression, boolean cached) {
416431
task = new FutureTask<Expression>(new Callable<Expression>() {
417432
@Override
418433
public Expression call() throws Exception {
419-
return innerCompile(expression);
434+
return innerCompile(expression, cached);
420435
}
421436

422437
});
@@ -429,7 +444,7 @@ public Expression call() throws Exception {
429444

430445
}
431446
else {
432-
return innerCompile(expression);
447+
return innerCompile(expression, cached);
433448
}
434449

435450
}
@@ -446,22 +461,23 @@ private static Expression getCompiledExpression(final String expression, FutureT
446461
}
447462

448463

449-
private static Expression innerCompile(final String expression) {
464+
private static Expression innerCompile(final String expression, boolean cached) {
450465
ExpressionLexer lexer = new ExpressionLexer(expression);
451-
CodeGenerator codeGenerator = newCodeGenerator();
466+
CodeGenerator codeGenerator = newCodeGenerator(cached);
452467
ExpressionParser parser = new ExpressionParser(lexer, codeGenerator);
453468
return parser.parse();
454469
}
455470

456471

457-
private static CodeGenerator newCodeGenerator() {
472+
private static CodeGenerator newCodeGenerator(boolean cached) {
458473
switch (optimize) {
459474
case COMPILE:
460-
ASMCodeGenerator asmCodeGenerator = new ASMCodeGenerator(aviatorClassLoader, traceOutputStream, trace);
475+
ASMCodeGenerator asmCodeGenerator =
476+
new ASMCodeGenerator(getAviatorClassLoader(cached), traceOutputStream, trace);
461477
asmCodeGenerator.start();
462478
return asmCodeGenerator;
463479
case EVAL:
464-
return new OptimizeCodeGenerator(aviatorClassLoader, traceOutputStream, trace);
480+
return new OptimizeCodeGenerator(getAviatorClassLoader(cached), traceOutputStream, trace);
465481
default:
466482
throw new IllegalArgumentException("Unknow option " + optimize);
467483
}
@@ -471,7 +487,7 @@ private static CodeGenerator newCodeGenerator() {
471487

472488
/**
473489
* Compile a text expression to Expression Object without caching
474-
*
490+
*
475491
* @param expression
476492
* @return
477493
*/
@@ -484,7 +500,7 @@ public static Expression compile(String expression) {
484500
* Execute a text expression with values that are variables order in the
485501
* expression.It only runs in EVAL mode,and it will cache the compiled
486502
* expression.
487-
*
503+
*
488504
* @param expression
489505
* @param values
490506
* @return
@@ -520,7 +536,7 @@ public static Object exec(String expression, Object... values) {
520536

521537
/**
522538
* Execute a text expression with environment
523-
*
539+
*
524540
* @param expression
525541
* text expression
526542
* @param env
@@ -541,19 +557,19 @@ public static Object execute(String expression, Map<String, Object> env, boolean
541557

542558
/**
543559
* Execute a text expression without caching
544-
*
560+
*
545561
* @param expression
546562
* @param env
547563
* @return
548564
*/
549565
public static Object execute(String expression, Map<String, Object> env) {
550-
return execute(expression, env, true);
566+
return execute(expression, env, false);
551567
}
552568

553569

554570
/**
555571
* Invalidate expression cache
556-
*
572+
*
557573
* @param expression
558574
*/
559575
public static void invalidateCache(String expression) {
@@ -563,7 +579,7 @@ public static void invalidateCache(String expression) {
563579

564580
/**
565581
* Execute a text expression without caching and env map.
566-
*
582+
*
567583
* @param expression
568584
* @return
569585
*/
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package com.googlecode.aviator.parser;
2+
3+
import java.util.HashMap;
4+
5+
import org.junit.Test;
6+
7+
import com.googlecode.aviator.AviatorEvaluator;
8+
9+
10+
public class AviatorClassLoaderUnitTest {
11+
12+
@Test
13+
public void testManyManyExpressions() {
14+
for (int i = 0; i < 10000; i++) {
15+
HashMap<String, Object> env = new HashMap<String, Object>();
16+
env.put("a" + i, i);
17+
env.put("b" + i, i-1);
18+
AviatorEvaluator.execute("a" + i + ">b" + i, env);
19+
}
20+
}
21+
}

src/test/java/com/googlecode/aviator/test/function/GrammarUnitTest.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import com.googlecode.aviator.AviatorEvaluator;
3939
import com.googlecode.aviator.exception.CompileExpressionErrorException;
4040
import com.googlecode.aviator.exception.ExpressionRuntimeException;
41+
import com.googlecode.aviator.exception.ExpressionSyntaxErrorException;
4142

4243

4344
/**
@@ -840,14 +841,14 @@ public void testTernaryOperator() {
840841
AviatorEvaluator.execute("!t? (i>0? f:ch) : f>3?email:ch)", env);
841842
Assert.fail();
842843
}
843-
catch (CompileExpressionErrorException e) {
844+
catch (ExpressionSyntaxErrorException e) {
844845

845846
}
846847
try {
847848
AviatorEvaluator.execute("!t? (i>0? f:ch : (f>3?email:ch)", env);
848849
Assert.fail();
849850
}
850-
catch (CompileExpressionErrorException e) {
851+
catch (ExpressionSyntaxErrorException e) {
851852

852853
}
853854
}

0 commit comments

Comments
 (0)