Подтвердить что ты не робот

RythmEngine и TemplateClassManager - самые большие объекты кучи: проблемы с утечкой памяти

В моей компании мы используем Rythm благодаря своему объекту и простому использованию в проекте. В нашем проекте мы отправляем несколько электронных писем (1000-2000 писем в день); шаблон электронной почты - это шаблон ритма с динамическим синтаксисом (код Java). Производительность кажется прекрасной, и она прошла тесты интеграции.

Тем не менее, мы экспериментировали с несколькими проблемами памяти, которые приводят к утечке памяти через 3-4 дня. Профилирование, мы заметили, что Rythm - самый большой объект кучи (наши профилирования составляют около 1 дня) даже больше, чем ClassLoader или BeanFactory от Spring.

Используя анализатор инструментов кучи, мы заметили, что 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 Root.

введите описание изображения здесь

Что касается пулов памяти: Par Eden кажется прекрасным, и CMS Old Generation, кажется, не увеличивается или, по крайней мере, медленно (даже после некоторых крупных GC, кажется, что свободная память). Память кучи кажется прекрасной (тесты и профилирование составляют около одного дня), но в производстве медленно возрастает после достижения максимальной кучи.

Мы спрашиваем, кто-то экспериментировал с этой функцией (используя ритм, а через несколько дней обнаруживает утечку памяти) или просто дайте некоторые рекомендации по повышению производительности с ритмом в производственной среде. Или любая идея о том, как бороться с утечкой памяти глубины, будет приветствоваться.

ВАЖНОЕ ЗАМЕЧАНИЕ [30-09-2015]: Мы изменили с Rythm на FreeMarker в качестве механизма шаблонов, и кажется (как наши системы мониторинга), что память более стабильна и составляет около 20% от максимальной памяти (-Xmx1024). Мы расскажем более подробно на этой неделе. Но, похоже, что у Rythm могут быть проблемы с памятью, которые через пару дней приводят к утечке памяти.

ВАЖНОЕ ПРИМЕЧАНИЕ [06-10-2015]: после нескольких дней интенсивного мониторинга мы проверили, что память стабильна с использованием FreeMarker в качестве механизма шаблонов. Мы удалили все зависимости Rythm в нашем продукте, потому что, поскольку наши исследования показывают , у него есть потенциальная проблема с утечкой памяти, которая не решена, которая через несколько дней движется к OOME для кучи ( в нашем случае два дня). Проблема закрыта.

4b9b3361

Ответ 1

Мы столкнулись и столкнулись с такой проблемой, но ее из-за компиляции шаблонов снова и снова. Чтобы этого избежать, мы выполнили следующие настройки: Включить режим работы Включить кэширование шаблонов Задайте скомпилированное расположение каталога шаблона - для хранения скомпилированной версии файлов шаблонов. (Не путайте с конфигурацией каталога шаблонов), что повысит скорость вашего приложения.

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);