2014-12-12 3 views
2

У меня есть проект Java 7, который запускает скрипты каждые n минут n процессами. Вот пример кода, который запускает скрипты.Обновление Groovy, вызывающее тонну мертвых GroovyClassLoaders в PermGen

ScheduledFuture scheduledFuture = scheduledService.scheduleAtFixedRate(new Runnable() { 
      @Override 
      public void run() { 
       try (GroovyClassLoader cl = new GroovyClassLoader()) { 
        // Load up reusable script modules in the class loader 
        Class scriptClass = cl.parseClass(scriptSource); 
        Foo script = optimizationClass.newInstance(); 

        // Tell Groovy that we don't need class meta info 
        GroovySystem.getMetaClassRegistry().removeMetaClass(scriptClass); 
        script.run(); 
        cl.clearCache(); 
       } catch (IOException e) { 
        LOGGER.error("Failed to cleanup Groovy class loader, this will cause a memory leak", e); 
       } 
      } 
     }, 0, scheduledRun, TimeUnit.SECONDS); 

     scheduledFuture.get(); 

По какой-то причине с Groovy 2.1.7 нет никакой утечки памяти в Перми Бытии При обновлении до Groovy 2.3.8 или 2.2.0 Groovy, Пермь Gen продолжает получать заполненные мертвыми Groovy класса погрузчиков.

0x000000071ada2cd0 33 488160 0x000000071b2493c8 dead groovy/lang/[email protected] 0x00000007265883b8 33 488160 0x0000000725837270 dead groovy/lang/[email protected] 0x00000007157b5da0 26 370736 0x000000072326f468 live org/codehaus/groovy/runtime/callsite/[email protected] 0x000000071ada1fb0 32 423944 0x000000071af03a98 dead groovy/lang/[email protected] 0x0000000719d605b0 32 456520 0x000000071af04798 dead groovy/lang/[email protected] 0x0000000725b82500 0 0 0x000000072326f468 dead groovy/lang/[email protected] 0x00000007263eef80 34 532448 0x0000000726d5c678 dead groovy/lang/[email protected] 0x000000072687b3c8 33 485288 0x0000000726c36340 dead groovy/lang/[email protected] 0x0000000725d56db0 33 485288 0x000000072607bcc0 dead groovy/lang/[email protected]

Я жду, пока Full GC не происходит, но это, кажется, что любая версия после Groovy 2.2 причиняло Пермь Gen завалить. Я проверил примечания к выпуску между версией, на которой я находился, до обновленной версии, и я не заметил никаких изменений, которые могли бы вызвать это.

Я проверил здесь для подобных вопросов и попробовал несколько предложений, но не повезло. Любые идеи относительно причины?

Обновление:
Я сделал Diff на GrepCode на GroovyClassLoader с 2.1.7 до 2.2.0 и не было изменений. Я также взял файл дампа кучи при запуске приложения и не было никаких путей к корням GC для сильных ссылок.

Проблема, кажется, здесь:

Class scriptClass = cl.parseClass(scriptSource); 
Foo script = scriptClass.newInstance(); 

Когда я не составляю сценарий, я получил 0 Groovy загрузчиков классов в Перми Ген Когда я компиляции сценария, но не запускайте его, я получаю Dead Groovy ClassLoaders.

Обновление:
Нашел код, вызывающий утечку.

Foo script = scriptClass.newInstance(); 

Не знаете, как это исправить, поскольку мне нужно создать новый экземпляр для запуска скрипта.

+0

Разве Java 8 не устраняет проблемы PermGen? :) (на самом деле меня тоже интересует, почему это произойдет!) –

+0

Java 8 заменила пространство PermGen на Metaspace, которое по умолчанию автоматически расширяет. Однако Java 8 ничего не делает о фактических утечках - вы все равно можете получить OutOfMemoryError: Metaspace. В случае, если вы хотите узнать, почему и как, не стесняйтесь ознакомиться с моей серией блога по теме: http://java.jiderhamn.se/2011/12/11/classloader-leaks-i-how -to-find-classloader-leaks-with-eclipse-memory-analyzer-mat/ –

+0

Обновление до Java 8 сейчас не является жизнеспособным решением на данный момент.Также это не решит проблему, почему обновление Groovy вызывает эту утечку. – ColinMc

ответ

0

У нас были схожие проблемы с файловым парсером, написанным в groovy, утечка памяти, как у seave, - когда вы делаете много манипуляций со строками. Мы также попробовали clearCache() для загрузчика классов, а также .removeMetaClass() без использования.

Мы, наконец, столкнулись с этой проблемой, собрав модуль groovy в виде файла jar и включив его в проект.

+0

К сожалению Я не могу использовать этот вариант, поскольку мне нужна треска Groovy e, чтобы быть вне приложения. Мы храним наш код Groovy в базе данных, и приложение запускает его. Это делается для того, чтобы инженеры могли мгновенно перераспределять код. – ColinMc

4

У меня была такая же проблема при использовании groovy script для компиляции и работы. я, наконец, работать с этим образом: 1. если вы работаете с Java версии под 7, вы можете использовать коды ниже, чтобы очистить свой класс после того, как составлен

public static void clearAllClassInfo(Class<?> type) throws Exception { 
    Field globalClassValue = ClassInfo.class.getDeclaredField("globalClassValue"); 
    globalClassValue.setAccessible(true); 
    GroovyClassValue classValueBean = (GroovyClassValue) globalClassValue.get(null); 
    classValueBean.remove(type); 
} 

2. В противном случае вам повезло, потому что вам просто нужно добавить свойства в SystemProperties

-Dgroovy.use.classvalue=true 
+0

Я искал исправление утечки, которое у меня было, и все, что я мог найти, было связано с статическим MetaClassRegistry. Но это не проблема. Я просто поставил эти варианты, и утечка исчезла. Похоже, в Groovy существует много разных утечек памяти при использовании в качестве компилятора времени выполнения. Большое спасибо! – caeus