killme2008 / aviatorscript

A high performance scripting language hosted on the JVM.
http://fnil.net/aviator/
4.64k stars 852 forks source link

动态生成大量不同的aviator表达式导致metaSpace OOM,FGC无法正确回收 #627

Closed Tofreedom7 closed 5 months ago

Tofreedom7 commented 5 months ago

java8 + 5.4.1+开启了cached 示例代码(模拟了下业务场景): public String testOOM() { log.info("testOOM"); Map<String, Object> map = Maps.newHashMap(); Random random = new Random(); long abc = random.nextLong()%10000000L; map.put("abc", new BigDecimal(abc)); try { while (true) { long cde = random.nextLong()%10000000L; String expression = "abc + " + cde; com.googlecode.aviator.Expression compiledExp = AviatorEvaluator.compile(expression, true); BigDecimal res = ((BigDecimal) compiledExp.execute(map)).setScale(0, RoundingMode.HALF_UP); log.info("res: {}, abc: {}, cde: {}, expression: {}", res, abc, cde, expression); } } catch (Exception e) { log.error("testOOM", e); return "fail|"+e.getMessage(); } } 代码原理是在死循环内 生成 abc + 随机数 的aviator的表达式,然后丢给aviator引擎做编译 大量生产aviator表达式造成metaSpaceOOM:

image

通过GC日志发现metaSpace空间大小无变化:

image

求各位大佬帮帮看看原因

killme2008 commented 5 months ago

你都完全随机了,还 cache 啥呢? cache 住就全部 class 都没办法被回收了。

Tofreedom7 commented 5 months ago

你都完全随机了,还 cache 啥呢? cache 住就全部 class 都没办法被回收了。

@killme2008 大佬,业务场景也有需要固定的表达式需要做缓存,这种场景下怎么处理合适呢?

Tofreedom7 commented 5 months ago

@killme2008 再请教下,为什么cache住就不会被GC回收了呢

killme2008 commented 5 months ago

那就固定的才 cache,不固定的就别去 cache,或者每次重新编译就调用下 invalidateCache 主动失效缓存

最佳实践都有介绍 https://www.yuque.com/boyan-avfmj/aviatorscript/ou23gy#PMc8K

killme2008 commented 5 months ago

@killme2008 再请教下,为什么cache住就不会被GC回收了呢

这个问题你应该去复习下 java gc 的机制。如果从 root 出发有 reference,怎么能回收呢? instance -> class

killme2008 commented 5 months ago

可以仔细看下最佳实践的缓存管理和匿名类卸载这块。 我先关闭了。

Tofreedom7 commented 5 months ago

@killme2008 再请教下,为什么cache住就不会被GC回收了呢

这个问题你应该去复习下 java gc 的机制。如果从 root 出发有 reference,怎么能回收呢? instance -> class

@killme2008 缓存不会自动清理吗?