2015-11-05 3 views
3

Я обнаружил серьезную утечку памяти в куске кода, который используется для компиляции и запуска кода Java во время выполнения. Я создал кучи кучи, и кажется, что виновником является com.sun.tools.javac.util.SharedNameTable$NameImpL.Утечка памяти в программе с использованием API-интерфейса компилятора

Что я хотел бы знать, так это то, как я могу предотвратить SharedNameTable от занимающего столько места. Есть ли способ принудительно освободить SharedNameTable?

enter image description here

код компилятора:

public static Object compile(String code) throws IOException, InvocationTargetException, IllegalAccessException, ClassNotFoundException, NoSuchMethodException, java.lang.InstantiationException { 
    String uuid = UUID.randomUUID().toString(); 
    File theDir = new File(uuid); 

    if (!theDir.exists()) { 
     System.out.println("creating directory: " + uuid); 
     boolean result = false; 

     try{ 
      theDir.mkdir(); 
      result = true; 
     } 
     catch(SecurityException se){ 
      System.out.println(se); 
     } 
     if(result) { 
      System.out.println("DIR created"); 
     } 
    } 
    //Compile 
    JavaCompiler jc = ToolProvider.getSystemJavaCompiler(); 
    StandardJavaFileManager sjfm = jc.getStandardFileManager(null, null, null); 
    JavaFileObject javaObjectFromString = getJavaFileContentsAsString(new StringBuilder(code)); 
    System.out.println(javaObjectFromString.getName()); 
    Iterable fileObjects = Arrays.asList(javaObjectFromString); 
    String[] options = new String[]{"-d", "/src/"+uuid}; 
    DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>(); 
    if (jc.getTask(null, null, diagnostics, Arrays.asList(options), null, fileObjects).call()) { 
     sjfm.close(); 
     System.out.println("Class has been successfully compiled"); 
     //Load 
     URL[] urls = new URL[]{new URL("file:///src/"+uuid+"/")}; 
     URLClassLoader ucl = new URLClassLoader(urls); 
     Class cl = ucl.loadClass("TestClass"); 
     System.out.println("Class has been successfully loaded"); 
     //Run 
     final Method method = cl.getDeclaredMethod("testMethod"); 
     final Object object = cl.newInstance(); 
     ExecutorService executor = Executors.newFixedThreadPool(1); 
     Callable<Object> task = new Callable<Object>() { 
      public Object call() throws IllegalAccessException, InvocationTargetException { 
       return method.invoke(object); 
      } 
     }; 
     Future<Object> future = executor.submit(task); 
     try { 
      Object result = future.get(20, TimeUnit.SECONDS); 
      return result; 
     } catch (TimeoutException ex) { 
      return "Method timed out (20 seconds). Please review your code."; 
     } catch (InterruptedException e) { 
      return "Method interrupted."; 
     } catch (ExecutionException e) { 
      e.printStackTrace(); 
      return String.format("ExecutionException thrown! %s", e.getMessage()); 
     } finally { 
      future.cancel(true); 
      executor.shutdown(); 
     } 
    } 
    sjfm.close(); 
    System.out.println("Class compilation failed!"); 
    //Create diagnostics and return them 
    List<String> errors = new ArrayList<>(); 
    for (Diagnostic diagnostic : diagnostics.getDiagnostics()){ 
     String s = String.format("[Code:%s] %s on line %d/column % d in %s", 
       diagnostic.getCode(), 
       diagnostic.getKind().toString(), 
       diagnostic.getLineNumber(), 
       diagnostic.getColumnNumber(), 
       diagnostic.getSource()); 
     errors.add(s); 
     errors.add(diagnostic.toString()); 
    } 
    return errors.toArray(); 
} 

Edit:

Я нашел similar question где SoftReference s укажут быть причиной проблемы. Принуждение к исключению OutOfMemoryException должно устранить их. Однако я запускаю этот код в приложении node.js, используя пакет «node-java» npm. Когда я пытаюсь заставить OoM, мое приложение node.js будет убито до того, как будет выброшено исключение.

+0

Что произойдет, если вы оставите КРП Постулаты пустой просто вызов 'jc.getTask (NULL, NULL, диагностику, Arrays.asList (опции), нулевой fileObjects) .call() '?? –

+0

Прошу прощения, я не уверен, правильно понял ваше предложение. Я попытался запустить 'jc.getTask (null, null, diagnostics, Arrays.asList (options), null, fileObjects) .call()' вне оператора if и не имел никакого результата при потреблении памяти. – Hartger

+0

Так что задача компиляции - не проблема. –

ответ

0

Как я писал в my answer до this question, существует опция компилятора, которая полностью исключает использование SharedNameTable. Вы можете просто добавить его в качестве дополнительной опции компилятора:

String[] options = new String[]{"-d", "/src/"+uuid, "-XDuseUnsharedTable"}; 

 Смежные вопросы

  • Нет связанных вопросов^_^