Генератор списков слов, ошибка размера кучи в Java

Я пытаюсь создать программу, которая генерирует список слов на основе пары (10-100) исходных входных слов. Конечный результат содержит миллионы, возможно, миллиарды строк, по одному слову в каждой строке. Я пришел достаточно далеко, чтобы я мог генерировать до 5 миллионов или около того слов, но всякий раз, когда я запускаю что-то, что генерирует гораздо больше слов, например, около 100 миллионов, программа вылетает примерно через 1 минуту и ​​9 секунд. Вот вывод ошибки:

    Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at java.util.Arrays.copyOf(Arrays.java:3210)
    at java.util.Arrays.copyOf(Arrays.java:3181)
    at java.util.ArrayList.grow(ArrayList.java:265)
    at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:239)
    at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:231)
    at java.util.ArrayList.add(ArrayList.java:462)
    at wordlistgen.WordlistGen2.combineWords(WordlistGen2.java:129)
    at wordlistgen.WordlistGen2.main(WordlistGen2.java:25)
    /home/NAME/.cache/netbeans/8.1/executor-snippets/run.xml:53: Java 
returned: 1
BUILD FAILED (total time: 1 minute 9 seconds)

Я попытался увеличить размер кучи для Netbeans, введя -J-Xms1024m -J-Xmx2048m в моем файле netbeans.conf (работает под управлением Ubuntu 17.10), но ошибка не исчезла.

По сути, программа импортирует оригинальные 10-100 слов:

static void importList() throws IOException{
    ArrayList<String> rawList = new ArrayList<>();

    try(BufferedReader br = new BufferedReader(new FileReader("textfile"))) {
        for(String line; (line = br.readLine()) != null; ) {
            rawList.add(line);
        }

        listOfLists.add(rawList);
        loll++;
    }

}

Затем, с помощью набора циклов for, я создаю новые варианты слов с заглавными буквами, числами в конце, подстроки всего слова и так далее. Слова хранятся в разных массивах, которые, в свою очередь, хранятся в ArrayList из ArrayLists. Так в ArrayList.

Когда я закончил комбинировать и манипулировать словами, я выводил весь конечный массив, строка за строкой, в выходной файл, используя следующий метод:

static void outputFile(String fileName) throws IOException{
    try (FileWriter writer = new FileWriter(fileName)) {
        for(String str: finalList) {
            writer.write(str +"\n");
        }
    }
}

Весь код можно найти здесь: https://pastebin.com/0fkvwYbx

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

1 ответ

Возможно, ArrayList не является подходящей реализацией List для вашей проблемы. Пожалуйста, смотрите: Когда использовать LinkedList поверх ArrayList?

Я думаю, что вы постоянно сталкиваетесь с наихудшим сценарием, когда (цитируя)

add (E element) амортизируется O(1), но в худшем случае O(n), так как размер массива должен быть изменен и скопирован

Не только неэффективно во времени, но и в памяти, поскольку вам постоянно нужны дублированные огромные массивы резервных копий для ваших списков ArrayLists. Рассмотрите возможность использования LinkedList, особенно если ваш код не выполняет произвольный доступ по индексу к спискам.

Другие вопросы по тегам