2012-04-15 4 views
0

У меня есть следующий класс JAVA для чтения из файла, содержащего много строк строк с разделителями табуляции. Пример строки, как следующее:JAVA обрабатывающий файл с java.lang.OutOfMemoryError: превышение верхнего предела GC превысило ошибку

GO:0085044  GO:0085044  GO:0085044 

код читать каждую строку и использовать функцию разделения положить три суб строк в массив, затем он положил их в хэш два уровня.

public class LCAReader { 
    public static void main(String[] args) { 
     Map<String, Map<String, String>> termPairLCA = new HashMap<String, Map<String, String>>(); 
     File ifile = new File("LCA1.txt"); 
     try { 
      BufferedReader reader = new BufferedReader(new FileReader(ifile)); 
      String line = null; 
      while((line=reader.readLine()) != null) { 
       String[] arr = line.split("\t"); 
       if(termPairLCA.containsKey(arr[0])) { 
        if(termPairLCA.get(arr[0]).containsKey(arr[1])) { 
         System.out.println("Error: Duplicate term in LCACache"); 
        } else { 
         termPairLCA.get(arr[0]).put(new String(arr[1]), new String(arr[2])); 
        } 
       } else { 
        Map<String, String> tempMap = new HashMap<String, String>(); 
        tempMap.put(new String(arr[1]), new String(arr[2])); 
        termPairLCA.put(new String(arr[0]), tempMap); 
       } 
      } 
      reader.close(); 
     } catch (IOException e) { 
      System.out.println(e.getMessage()); 
     } 
    } 
} 

Когда я запустил программу, я получил следующую ошибку времени выполнения после некоторого времени работы. Я заметил, что использование памяти постоянно растет.

Исключение в потоке "основного" java.lang.OutOfMemoryError: предел ГХ накладных расходов превысил на java.util.regex.Pattern.compile (Pattern.java:1469) в java.util.regex.Pattern (Pattern. .java: 1150) на java.util.regex.Pattern.compile (Pattern.java:840) на java.lang.String.split (String.java:2304) на java.lang.String.split (строка .java: 2346) at LCAReader.main (LCAReader.java:17)

Входной файл почти 2G, а машина, на которой я запускал программу, имеет память 8G. Я также попробовал параметр -Xmx4096m для запуска программы, но это не помогло. Поэтому я думаю, что в моем коде есть утечка памяти, но я не могу их найти.

Может ли кто-нибудь помочь мне в этом? Заранее спасибо!

ответ

3

Нет утечки памяти; вы просто пытаетесь хранить слишком много данных. 2 ГБ текста будет занимать 4 ГБ ОЗУ в качестве символов Java; плюс около 48 байт на служебные данные объекта String. Предполагая, что текст находится в 100 символьных строках, есть еще один GB, всего 5 ГБ, и мы еще не подсчитали объекты Map.Entry! Вам понадобится куча Java, по крайней мере, консервативно, 6 ГБ для запуска этой программы на ваши данные и, возможно, больше.

Есть несколько простых вещей, которые вы можете сделать, чтобы улучшить это. Во-первых, потеряйте конструкторы new String() - они бесполезны и просто заставляют сборщик мусора усердно работать. Строки неизменяемы, поэтому вам не нужно их копировать. Во-вторых, вы можете использовать внутренний пул для обмена повторяющимися строками - это может или не поможет, в зависимости от того, как на самом деле выглядят данные. Но вы могли бы попробовать, например,

tempMap.put(arr[1].intern(), arr[2].intern()); 

Эти простые шаги могут помочь.

+2

Одно слово предостережения о переходе 'new String()' при использовании 'String.split()'. Если вам нужны только несколько токенов из результатов 'String.split()', часто бывает неплохо использовать 'new String()', потому что 'Strings', возвращаемые' String.split() ', являются просто обертками, которые верните все строки разделения. Таким образом, вы оставите свою целую цепочку в куче, когда все, что вам нужно, - это несколько ее частей (здесь не так много, потому что он использует все в 'String', но' 't' separators). – ulmangt

+0

Я пробовал метод intern() и увеличил размер кучи до 6G, и никаких исключений не было. Из использования памяти я вижу, что он все еще использует много памяти. Таким образом, увеличение размера кучи помогло, и метод intern() мало помог. Благодаря! – Wei

0

Я не вижу утечки, вам просто нужен очень большой объем памяти для хранения вашей карты. Существует очень хороший инструмент для проверки этого: создание дампа кучи с опцией - XX: + HeapDumpOnOutOfMemoryError и импортировать его в Eclipse Memory Analyzer, который поставляется в автономной версии. Он может показать вам самые большие сохраненные объекты и дерево ссылок, которые могут помешать сборщику мусора выполнять свою работу. Кроме того, профилировщик, такой как Netbeans Profiler может предоставить вам много интересной информации в реальном времени (например, чтобы проверить количество экземпляров String и Char).

Также рекомендуется разделить свой код на разные классы, каждый из которых имеет различную ответственность: класс «двух ключей» (TreeMap) с одной стороны и класс «парсер» на другой стороне, он должен сделать отладка проще ...

Это, безусловно, не очень хорошая идея для хранения этой огромной карты внутри ОЗУ ...или вам нужно сделать скамье с меньшими файлами и экстраполировать, чтобы получить оценочную оперативную память, необходимую для вашей системы в соответствии с вашим деловым случаем ... И установите Xmx в правильное значение. Почему вы не используете Хранилище ключевых значений, такое как Berckley DB: проще, чем реляционная БД, и должно соответствовать точно вам нужно индексирование двух уровней. Проверить эту должность по выбору магазина: key-value store suggestion

Удачи

0

Вы, вероятно, не следует использовать String.split и хранить информацию, как чистый String, как это порождает множество String объектов на лету.

Попробуйте использовать подход на основе char, так как ваш формат кажется довольно фиксированным, чтобы вы знали точные индексы различных точек данных на одной строке.

Если вы немного экспериментируете, вы можете попытаться использовать подход с поддержкой NIO с отображенной памятью DirectByteBuffer или CharBuffer, которая используется для перемещения по файлу. Там вы можете просто пометить индексы различных точек данных в объекты Marker и загружать только реальные данные String в процессе, когда это необходимо.

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