2015-05-13 6 views
1

Моя программа выполняет итерацию по каталогу и использует следующую функцию из моего класса Recoder для чтения файла с использованием FileUtils.readFileToString по кодировке и перезаписывает он использует FileUtils.write на другой кодировке.«java.lang.OutOfMemoryError: Java heap space» При вызове FileUtils.readFileToString в xml-файлах

Однако, когда он пытается сделать это с помощью xml-файла, я получаю исключение в заголовке, в противном случае он отлично работает (я тестировал в каталоге с .java, .js, .css, .html, .jsp ...).

public class Recoder { 
    private static Charset fromCharset; 
    private static Charset toCharset; 

    public static void recodeToUTF(File f, boolean verbose){ 
     try{ 
      if(verbose){ 
       System.out.println("Convertendo "+f.getAbsolutePath()+" para UTF-8"); 
      } 
      toCharset = Charset.forName("UTF-8"); 
      String content = FileUtils.readFileToString(f); 
      FileUtils.write(f,content, toCharset); 
     }catch(Exception e){  
     } 
    } 

    public static void recodeFile(File f, String de, String para, boolean verbose){ 
     try{ 
      if(verbose){ 
       System.out.println("Convertendo "+f.getAbsolutePath()+" de "+ de + " para "+ para); 
      } 
//   CharsetDetector cd= new CharsetDetector(); 
//   FileInputStream fis = new FileInputStream(f); 
//   cd.setText(fis); 
//   fis.close(); 
//   CharsetMatch cm = cd.detect(); 

//   if(cm!=null){ 
//    fromCharset = Charset.forName(cm.getName()); 
//   }else{ fromCharset = Charset.forName(de);} 
      fromCharset = Charset.forName(de); 
      toCharset = Charset.forName(para); 
      String content = FileUtils.readFileToString(f,fromCharset); 
      FileUtils.write(f,content,toCharset); 
      content=null; 
     }catch(Exception e){  
     } 
    } 

    public static String removeAcentos(String str) { 
     str = Normalizer.normalize(str, Normalizer.Form.NFD); 
     str = str.replaceAll("[^\\p{ASCII}]", ""); 
     return str; 
    } 

} 

CharsetDetector материал из ICU4J, и по какой-то причине он зависает при вызове cd.detect() так, сейчас я просто оставил его в комментариях.

Это главное, что это называет:

public static void main(String[] args){ 
     DecoderArguments decArgs = new DecoderArguments(); 
     JCommander jc = new JCommander(decArgs, args); 
     try { 
      if(args.length>0){ 
       for(String s : decArgs.files){ 
        File file; 
        if (decArgs.recursive){ 
         System.out.println("Executando Recursivamente em: "+ s); 
         file = new File(s); 
         if(file.isDirectory()){ 
          Collection<File> files = FileUtils.listFiles(file,FileFileFilter.FILE, DirectoryFileFilter.DIRECTORY); 
          for (File f : files){ 
           boolean exec=true; 
           for(String excl : decArgs.excludes){ 
            if (f.getAbsolutePath().contains(excl)) exec=false; 
           } 
           if (file.exists() && exec){ 
            if("".equals(decArgs.fromEncoding)){ 
             Recoder.recodeToUTF(f, decArgs.verbose); 
            }else { 
             Recoder.recodeFile(f, decArgs.fromEncoding, decArgs.toEncoding, decArgs.verbose); 
            } 
            System.gc(); 
           }       
          } 
         }else{ 
          System.out.println("Por favor, informe um diretorio para ler recursivamente.\n" 
            + "Uso: java -jar decoder.jar <-r> Caminho|Arquivo"); 
         }  
        }else{ 
         System.out.println("Convertendo arquivo: "+ s); 
         file = new File(s); 
         boolean exec=true; 
         for(String excl : decArgs.excludes){ 
          if (file.getAbsolutePath().contains(excl)) exec=false; 
         } 
         if (file.exists() && exec){ 
          if("".equals(decArgs.fromEncoding)){ 
           Recoder.recodeToUTF(file, decArgs.verbose); 
          }else { 
           Recoder.recodeFile(file, decArgs.fromEncoding, decArgs.toEncoding, decArgs.verbose); 
          } 
         } 
        } 
       } 
      }else if (args.length==0){ 
       System.out.println("Sintaxe incorreta.\n"); 
       jc.usage(); 
      } 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 

Things отметить:

  • Я использую следующие параметры виртуальной машины на Eclipse, -Xms1024m -Xmx2048m
  • JDK версии 1.7. 0_75
  • Я экспериментировал с некоторыми System.gc(), но безрезультатно
  • Это происходит только тогда, когда основной работает рекурсивно (decArgs.recursive=true), тот же файл, который генерирует исключение, перекодируется плавно, когда
  • Уже проверено кодирование файла на bash и жестко закодировано для теста, и удачи там нет.

Любые идеи о том, почему это происходит?

Заранее благодарен!

EDIT: Использование Recoder.recodeToUTF метод вместо Recoder.recodeFile вызывает не OutOfMemory не быть выброшен. Возможно, попытка открыть с неправильной кодировкой вызывает утечку памяти.

Анализ созданного .hprof файла (messed up) 300Mb xml использовал около 500 Мб кучи. Тем не менее, куча установлена ​​на максимальный размер 2Gb

+0

Насколько велики файлы? Килобайт? Мегабайт? Гигабайт? Зачем вам читать их полностью, что кажется очень расточительным, вы можете попробовать обработать их как поток (читайте немного, напишите немного, ...). И последнее, но не менее важное: если вы просто «перекодируете» файл XML без исправления заголовка, то он может легко закончиться неверно: если заголовок упоминает другую кодировку, чем то, что на самом деле используется, подтверждающий синтаксический анализатор XML * должен * сообщить об этом как ошибка (если она может обнаружить это). –

+0

большинство находится в Кб, некоторые в нескольких Мб, но по какой-то причине был pom.xml с 300 МБ, очень странный. Я читаю весь файл сразу только для удобства, пока не нашел Файловый поток, где я мог бы играть с кодировками, любыми предложениями? Я в настоящее время заменяю кодировку из XML-файлов на eclipse, но я планирую вставить ее в код очень скоро. Благодаря! –

ответ

1

Ваша память просочилась, поэтому, чтобы проверить эту проблему, вы можете настроить JVM с этими параметрами -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/path/to/dump. Когда OutOfMemoryError будет сброшен, дамп будет создан в /path/to/dump. Затем вы можете проанализировать его с помощью Eclipse Memory Analyzer и искать объекты, которые перегружают вашу память. Nice tutorial here

+0

Спасибо, я попробую.(может отметить проголосовать) –