java.lang.Ошибка OutOfMemoryError в java

#java #memory #out-of-memory

#java #память #нехватка памяти

Вопрос:

Я написал программу на Java, в которой я должен знать, что если два вложенных цикла for могут завершить свое выполнение за 4 секунды или нет, если они завершат свое выполнение за 4 секунды, тогда программа должна продолжить, иначе разорвать цикл. У меня есть три списка A, B и C, и я выполняю некоторую операцию и добавляю ее в список B. Даже для небольших входных данных в список A и C, таких как 3, 6, 8, 4, моя программа выдает run out of memory error

Я использую один внешний цикл for для вычисления времени. Если два цикла for не смогли завершить свое выполнение за 4 секунды, цикл должен быть завершен. Я использую одну переменную count для отслеживания выполнения цикла for, даже если цикл for завершил свое выполнение до 4 секунд, когда я завершаю внешний цикл for.
Вот мой код :

 while(!(A.isEmpty())){
    ArrayList<Long> B = new ArrayList<>();
    for(long start = System.currentTimeMillis() ; start < System.currentTimeMillis()   4 * 1000 ; ){
        for(long i : A){
            for(long j : C){
                if(i!=j){
                    B.add(Math.abs(i-j));
                }
            }
            count  ;
            if(count==A.size());
                break;
        }
    }
}
 

Что не так с этим кодом? Как я должен исправить это?
Спасибо.

Комментарии:

1. Это бесконечный цикл, потому что вы не написали start или что-то подобное в своем цикле. Я полагаю, что в конце концов у вас закончится память.

2. Даже если я увеличу start, он все равно не получит результат. Я смущен тем, что это лучший способ проверить, что вложенный цикл for может завершить свое выполнение за 4 секунды или нет?

3. Ваша проблема в том, что вы что-то путаете. Вы хотите А) что-то вычислить Б) измерить некоторое время. Как указано в моем ответе, вы должны разделить эти две проблемы!

4. Значение start всегда будет меньше значения, возвращаемого System.currentTimeMillis() в тестовом условии вашего внешнего цикла for. Весь этот шаблон выглядит ужасно, но если вы настаиваете на его использовании, попробуйте создать end время, равное текущему времени плюс четыре секунды, а затем измените условие тестирования цикла for на System.currentTimeMillis() < end .

5. Если я правильно понимаю, что вы пытаетесь сделать, это продолжать добавлять данные в ArrayList в течение 4 секунд, а затем остановиться? В чем смысл этого? И вы можете добавить много элементов за 4 секунды, конечно, вам не хватит памяти для их хранения, если у вас много памяти.

Ответ №1:

Я думаю, что этот дизайн не очень надежный. Вместо вызова функции time в этом цикле, я думаю, вы могли бы использовать здесь два потока:

  1. Поток A запускает поток B и ожидает n секунд
  2. Поток B выполняет вычисления
  3. Когда поток A просыпается, он просто проверяет, выполнено ли вычисление

В качестве альтернативы, ваш основной поток запускает A и B; и A просто возвращается и сообщает вам: время проверить результаты B сейчас.

И для вашей реальной проблемы; Я думаю, здесь есть один участник:

 B.add(Math.abs(i-j));
 

Вы видите, что B (действительно плохое название для списка чисел, кстати!) занимает длинные объекты. Таким образом, этот небольшой вызов создает по крайней мере один длинный объект за итерацию. И вы выполняете итерацию по A и C. Без каких-либо задержек или задержек. Это означает, что ваш код не делает ничего другого, кроме повторения циклов и создания новых объектов для заполнения этого списка B.

Теперь: как вы думаете, сколько итераций цикла вы увидите за 4 секунды? Достаточно для создания миллионов и миллионов объектов ?! И затем: динамически растущий список хорош, но вы понимаете, что это значит, когда ArrayList постоянно превышает свою емкость и должен расти ?! Вы понимаете, что это означает создание новых массивов и копирование всех значений ?!

Я хочу сказать: внимательно посмотрите, сколько работы там действительно происходит; и сколько (не) боксов примитивных / ссылочных длинных / длинных вы получили в своем коде.

Один (возможно, простой способ) проверить эти идеи: измените свой код с использования List of Longs на использование фиксированных массивов с длинными значениями. Это будет иметь приятный побочный эффект — это заставит вас заранее подумать о том, сколько слотов массива вы на самом деле хотите создать. В вашем решении вы просто продолжаете цикл и добавляете новые объекты (как сказано; что приводит к постоянным операциям увеличения емкости для вашего списка B).

Ответ №2:

Оператор while(!(A.isEmpty())) запустит бесконечный цикл, в результате чего экземпляр B будет создаваться бесконечное количество раз.

В результате чего OutOfMemoryError

Комментарии:

1. Предполагая, что gc выполняет свою работу, воссоздание локальной переменной в бесконечном цикле не приведет к возникновению исключения нехватки памяти

2. @LucasKot-Zaniewski Все зависит от того, сколько мусора создается за итерацию цикла. Видите ли, если ваш процессор работает на полной скорости через эти циклы, и каждый цикл создает только один объект, который должен быть «удален». .. ни один GC в мире не сможет идти в ногу с этим. Для выполнения GC требуется время . И у вас нет того времени, когда ваш код не делает ничего другого, кроме как создавать мусор!

3. …и gc не запускается или, по крайней мере, не может зависеть от запуска, последовательно или постоянно.

4. В настоящее время я запускаю бесконечный цикл только с одной объявленной переменной ArrayList (добавляя к ней 100 строк с каждой итерацией) и ссылаюсь на нее позже, чтобы узнать, сколько времени потребуется, прежде чем GC не сможет идти в ногу… Я подозреваю, что это займет довольно много времени, но я обновлю результат. В любом случае это не проблема, с которой столкнулся OP, как вы указали

5. Все еще работает хорошо, даже повысил ставку до 100 миллионных строк, как видно из чтения этого ibm.com/developerworks/library/j-leaks этот GC предотвратит наличие в программе ООМ в этом сценарии, поэтому, если вы запустите цикл миллион раз между циклами GC, то создадите список массивов размером в миллион 1, помеченный как мусор, почему это соотношениеизменение? Даже если бы у вас был сверхмощный процессор, это также ускорило бы сборку. Дело в том, что если вы создаете сверхбольшие объекты в своем цикле, то GC будет занимать все больше и больше времени, но и ваш цикл тоже.

Ответ №3:

У вас бесконечный цикл, while(!(A.isEmpty)) всегда будет true, потому что внутри ваших циклов for вы никогда не удаляете какие-либо элементы из A. Это приведет к добавлению бесконечного количества элементов в B из-за B.add(Math.abs(i-j));

Комментарии:

1. Хотя вы правы, говоря, что это бесконечный цикл (при условии однопоточной программы), это не вызывает исключения нехватки памяти, потому что B переопределяется каждый раз, когда выполняется этот внешний цикл, поэтому он не будет добавлять бесконечные элементы в B.