在我的公司中,由于Rythm的便利性和在项目中的易于使用,我们正在使用它。
在我们的项目中,我们要发送几封电子邮件(每天发送1000-2000封电子邮件);电子邮件模板是具有动态语法(Java代码)的Rythm模板。性能似乎不错,并且通过了集成测试。
不过,我们已经尝试了一些内存问题,这些问题会在3-4天后导致内存泄漏。分析,我们发现Rythm是堆中最大的对象(我们的分析大约是1天),甚至比Spring中的ClassLoader或BeanFactory还多。
使用堆工具分析器,我们观察到 RythmEngine 和 TemplateClassManager 是最大的对象
(Instance) - (retained size bytes)
org.rythmengine.RythmEngine#1 - 10,192,894
org.rythmengine.internal.compiler.TemplateClassManager#1 - 9,223,065
org.springframework.boot.loader.LaunchedURLClassLoader#1 - 6,975,661
java.util.Vector#89 - 6,378,290
java.lang.Object[]#7549 - 6,378,254
org.springframework.beans.factory.support.DefaultListableBeanFactory#1 - 3,741,643
......
从堆分析器工具中我们可以看到这些对象是大对象,并且似乎随着时间的推移它们会增加。
还有一个GC根。
关于内存池:Par Eden看起来不错,而CMS Old Generation似乎没有增加,或者至少没有缓慢增加(即使在一些主要的GC之后,似乎还有可用内存)。堆内存似乎很好(测试和分析大约是一天),但是达到最大堆后,生产速度会缓慢增加。
我们正在询问是否有人尝试了此功能(使用节奏,几天后出现内存泄漏),或者只是给出一些在生产环境中如何通过节奏提高性能的最佳实践。或者欢迎任何有关如何处理深度内存泄漏的想法。
重要说明 [30-09-2015]:我们已将Rythm更改为FreeMarker,将其作为模板引擎,并且(正如我们的监控系统所反射(reflect)的),内存似乎更稳定,大约是最大内存的20% (-Xmx1024)。我们将在本周内提供更详细的信息。但是似乎Rythm可能存在一些内存问题,几天后它会导致内存泄漏。
重要说明 [06-10-2015]:经过几天的深入监控,我们检查了使用FreeMarker作为模板引擎的内存是否稳定。 我们已经删除了产品中所有Rythm的依赖项,因为当我们的研究反射(reflect)时,它存在潜在的内存泄漏问题,无法解决,该问题在几天后(在我们的情况下为两天)驱动到OOME进行堆。问题已结案。
最佳答案
我们也面临并遇到过这样的问题,但这是因为模板的编译一次又一次。为避免这种情况,我们进行了以下设置,
启用产品模式
启用模板缓存
设置模板编译目录位置-存储模板文件的编译版本。 (不要与模板目录配置混淆),这将提高您的应用程序速度。
Map<String, Object> rythmConfigs = new HashMap<>();
//rythmConfigs.put(ENGINE_MODE, this.appMode ? "prod" : "dev");
rythmConfigs.put(PRECOMPILE_MODE_ENABLED, this.config.getBoolean(PRECOMPILE_MODE_ENABLED, true));
rythmConfigs.put(LOAD_PRECOMPILED_ENABLED, this.config.getBoolean(LOAD_PRECOMPILED_ENABLED, true));
rythmConfigs.put("rythm.default.cache_ttl", Integer.MAX_VALUE);
rythmConfigs.put("rythm.cache.enable", this.appMode);
//rythmConfigs.put("cache.prod_only.enabled", this.appMode);
rythmConfigs.put(PRECOMPILED_DIR, getTempDir(config.getString(XoAppConfigKeys.APPLICATION_CONTEXT)).getAbsolutePath());
rythmConfigs.put(TEMPLATE_DIR, this.templateFolderUri.getPath());
rythmEngine = new RythmEngine(rythmConfigs);