2013-07-30 3 views
0

У меня есть большой файл txt с целыми числами в нем. Каждая строка в файле имеет два целых числа, разделенных пробелами. Размер файла - 63 Мб.Java outOfMemory exception в string.split

Pattern p = Pattern.compile("\\s"); 
    try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) { 
     String line; 
     while ((line = reader.readLine()) != null) { 
      String[] tokens = p.split(line); 
      String s1 = new String(tokens[0]); 
      String s2 = new String(tokens[1]); 
      int startLabel = Integer.valueOf(s1) - 1; 
      int endLabel = Integer.valueOf(s2) - 1; 
      Vertex fromV = vertices.get(startLabel); 
      Vertex toV = vertices.get(endLabel); 
      Edge edge = new Edge(fromV, toV); 
      fromV.addEdge(edge); 
      toV.addEdge(edge); 
      edges.add(edge); 
      System.out.println("Edge from " + fromV.getLabel() + " to " + toV.getLabel()); 
     } 

    } catch (IOException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space 
at java.util.Arrays.copyOfRange(Arrays.java:2694) 
at java.lang.String.<init>(String.java:203) 
at java.lang.String.substring(String.java:1913) 
at java.lang.String.subSequence(String.java:1946) 
at java.util.regex.Pattern.split(Pattern.java:1202) 
at java.util.regex.Pattern.split(Pattern.java:1259) 
at SCC.main(SCC.java:25) 

Почему я получаю это исключение? Как я могу изменить свой код, чтобы избежать его?

EDIT: Я уже увеличил размер кучи до 2048 м. Что его поглощает? Это то, что я хотел бы знать также.

Для всего, что я знаю, jvm должен выделять память на список вершин, набор ребер, буфер для буферизованного считывателя и одну маленькую строку «строка». Я не вижу, откуда эта outOfMemory.

Я прочитал о методе string.split(). Я думаю, что это вызывает утечку памяти, но я не знаю, что мне делать с этим.

+1

Я думаю 'p.split (строка);' должен быть 'line.split (" \\ s + ");' – Smit

+0

@Smit Нет, это попытается разбить строку "\ s +" на шаблон '\ s'. – erickson

+1

@erickson это wouldnt. Посмотрите на метод String.split() в API. Хотя Pattern.split() должен вести себя точно так же, так что вы действительно ошибаетесь ... – gnomed

ответ

4

Что вы должны попробовать первым, это уменьшить файл до достаточно малого, чтобы он работал. Это позволит вам оценить, насколько велика ваша проблема.

Во-вторых, ваша проблема определенно не связана с String#split, так как вы используете ее только по одной строке за раз. То, что потребляет ваша куча, - это Vertex и Edge экземпляров. Вам придется переделать это на меньшую площадь или полностью перестроить свои алгоритмы, чтобы иметь возможность работать только с частью графика в памяти, а остальное на диске.

P.S. Просто общий Java примечание: не пишите

String s1 = new String(tokens[0]); 
String s2 = new String(tokens[1]); 

вам просто нужно

String s1 = tokens[0]; 
String s2 = tokens[1]; 

или даже просто использовать tokens[0] непосредственно вместо s1, так как это примерно так же ясно.

+0

Я знаю это, я только что прочитал, что использование токенов [0] дает GC от удаления символов из памяти. – user1685095

+2

Запись 'new String (...)' не может ничего хорошего, кроме выделения еще большего объема памяти. –

+0

Да, в моем случае я думаю, что это так. – user1685095

3

Самый простой способ: увеличить размер кучи: Добавить -Xmx512m -Xms512m (или даже более) аргументы Jvm

+2

Является ли ОП запросом на увеличение памяти? Это комментарий, а не ответ. – Makky

+0

Это уже 2048м. – user1685095

2

Увеличение лимита кучи памяти, используя опцию -Xmx JVM.

Подробнее here.

+2

Является ли ОП просящим увеличить память? Это комментарий, а не ответ. – Makky

+1

Почему это не ответ? Я не вижу утечки памяти здесь. – Divers

+2

^Читайте вопрос. – Makky

0

У вас есть исключение, потому что вы закончили свое кучное пространство. Попробуйте увеличить кучу с помощью

java -Xms512 -Xmx2048 (for example) 
0

Когда вы когда-либо получаете OOM при попытке разобрать материал, его просто то, что используемый вами метод не является масштабируемым. Хотя увеличение кучи может временно решить проблему, она не масштабируется. Например, если завтра размер вашего файла будет увеличен на порядок или величину, вы вернетесь в квадрат. Я бы рекомендовал попробовать прочитать файл в кусках, кешировать строки x файла, прочитать его, очистить кэш и повторно выполнить этот процесс. Вы можете использовать кеш ehcache или guava.

2

Вы получаете это исключение, потому что ваша программа хранит слишком много данных в куче java.

Хотя ваше исключение проявляется в методе Pattern.split(), фактическим виновником может быть любой большой пользователь памяти в вашем коде, такой как построенный граф. Глядя на то, что вы предоставили, я подозреваю, что структура данных графа хранит много избыточных данных. Возможно, вам захочется исследовать более пространственную структуру графа.

Если вы используете Sun JVM, попробуйте опцию JVM -XX: + HeapDumpOnOutOfMemoryError, чтобы создать кучу кучи и проанализировать это для любых тяжелых пользователей памяти и использовать этот анализ для оптимизации вашего кода. См. Using HeapDumpOnOutOfMemoryError parameter for heap dump for JBoss для получения дополнительной информации.

Если это слишком много для вас, как указали другие, попробуйте увеличить пространство кучи JVM до точки, где ваша программа больше не сработает.

0

Способ, которым вы разбираете строку, может быть изменен.

try (Scanner scanner = new Scanner(new FileReader(filePath))) { 
    while (scanner.hasNextInt()) { 
     int startLabel = scanner.nextInt(); 
     int endLabel = scanner.nextInt(); 
     scanner.nextLine(); // discard the rest of the line. 
     // use start and end. 

    } 

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

+1

Разве это немного хрупко, поскольку оно не устойчиво к ошибочному третьему целому числу в одной строке? Я бы чувствовал себя более уверенно, если бы я сначала взял линию, а затем разделил ее. Я думаю, что это легко выполнимо и с «Сканером». –

+0

@MarkoTopolnik Я собирался справиться с этим, но забыл. Исправлено. –

+0

Ну, hasNexInt() возвращает false немедленно ... Я тоже думал об этом решении, но думал, что сканер также использует раскол и шаблоны в своей работе, поэтому я думал, что это не поможет. – user1685095

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