2017-01-04 18 views
2

В приложении я неоднократно создаю экземпляры GroovyShell и запускаю на них собственные скрипты. При этом возникают проблемы, связанные с тем, что пространство perm gen в Java 6 и Java 7 заполняется, а классы не выгружаются. Я использую Groovy 2.4.7. Проблема может быть воспроизведена с помощью следующего кода:Повторное использование Groovy Shells приводит к заполнению пространства PermGen

import groovy.lang.GroovyShell; 

public class Demo { 


    public static void main(String[] args) throws Exception { 
     for (int i = 0; i < 10000000; i++) { 
      GroovyShell gs = new GroovyShell(); 
      Object result = gs.evaluate(" 'Hello, World';"); 
      assert result.equals("Hello, World"); 
     } 
    } 
} 

Я использую следующие VM аргументы:

-verbose:class -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+CMSClassUnloadingEnabled -XX:+ExplicitGCInvokesConcurrentAndUnloadsClasses -XX:+TraceClassUnloading -XX:MaxPermSize=16M -XX:+UseConcMarkSweepGC -XX:+ExplicitGCInvokesConcurrent -XX:+PrintGCDetails -XX:-UseParNewGC 

Когда я выполнить тест из выше, PermGen полна после того, как чуть более 2000 итераций , Кроме того, запуск GC вручную не работает.

Есть ли способ принудительно разгрузить класс или запустить GC, чтобы классы были удалены из пространства PermGen?

ответ

1

Woah. Задержать. Я просто дал this one быстрый выстрел, и, похоже, он отлично работает. Вместо того, чтобы напрямую использовать оболочку, вы скомпилируете скрипт и запустите сценарий (для того же результата). Затем вызовите указанный очиститель.

public static void test() { 
    for (int i = 0; i < 10000000; i++) { 
     GroovyShell gs = new GroovyShell(); 
     Script script = gs.parse(" 'Hello, World';"); 
     Object result = script.run(); 
     assert result.equals("Hello, World"); 
     clearAllClassInfo(script.getClass()); 
    }     
} 

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

Очевидно, что вы можете немного оптимизировать уборщик, чтобы устранить кучу отражения.

PermGen довольно плоский: enter image description here

И классы разгружаются в быстром темпе: enter image description here

Кредит @BilboDai.

+0

Спасибо @ Николас! Я тестировал это с помощью Java 6 и 7, а классы были выгружены как версиями вариантов, так и в многопоточных сценариях. Тем не менее, я создам дефект на Groovy Jira, потому что, по моему мнению, это должен обрабатывать сам Groovy, а не его пользователи. –

0

Повторное использование экземпляра GroovyShell:

import groovy.lang.GroovyShell; 

public class Demo { 


    public static void main(String[] args) throws Exception { 
     //Create outside the loop 
     GroovyShell gs = new GroovyShell(); 
     for (int i = 0; i < 10000000; i++) { 
      Object result = gs.evaluate(" 'Hello, World';"); 
      assert result.equals("Hello, World"); 
     } 
    } 
} 
+0

К сожалению, этот подход приводит к тому же поведению, что и в моем примере. –

2

Я могу посочувствовать, так как я боролся с этим на некоторое время. Я реализовал this solution, и это улучшило срок службы PermGen в Java 1.6, но не устранило основную проблему.

По какой-то причине я не вижу проблемы на Java 8, поэтому я отказался от попытки работать. (Не пробовал с Java 7).

Надеюсь, вы сможете добраться дальше, чем я.