java.util.Sublist бросая StackOverFlowError - PullRequest
5 голосов
/ 24 сентября 2010

Мы получаем случайные ошибки StackOverFlowError в производственной среде, связанные с выполнением операции SubList. Кто-нибудь видел что-то подобное раньше и знает, что может быть причиной?

Это вызываемый код, который вызывает ошибку:

  FacesContext context = FacesContext.getCurrentInstance();
    String newViewID = context.getViewRoot().getViewId();

    if (newViewID != null) {
     if (breadCrumbs.contains(newViewID)) {
      // Trims the list upon going back to allow for multiple back button requests.  
      // This is lightweight and not intended for a complex circular navigation.
      breadCrumbs = breadCrumbs.subList(0, breadCrumbs.indexOf(newViewID) + 1);
     } else {
      breadCrumbs.add(newViewID);
     }
    }

Результат:

Caused By: java.lang.StackOverflowError
 at java.util.SubList$1.<init>(AbstractList.java:688)
 at java.util.SubList.listIterator(AbstractList.java:687)
 at java.util.SubList$1.<init>(AbstractList.java:688)
 at java.util.SubList.listIterator(AbstractList.java:687)
 ...

Ответы [ 6 ]

6 голосов
/ 24 сентября 2010

Метод subList () возвращает представление , подкрепленное исходным списком .

Согласно javadoc:

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

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

2 голосов
/ 08 мая 2014

У меня была точно такая же проблема с использованием стандартной библиотеки LinkedList и fastutil objectarraylist (fastutil - это быстрая и эффективная реализация памяти для инфраструктуры сбора Java).

Использование

window = window.subList(index+1, window.size());

вызвало ошибку переполнения стека. Я заменил на

window = new LinkedList<>( window.subList(index+1, window.size()) );

и все работало нормально.

Надеется, что это может помочь

0 голосов
/ 27 мая 2013

Проблема заключается в том, как AbstractList.java (базовый класс ArrayList) реализует метод subList.Он создает подсписок (он же вид) с помощью родительского указателя, смещения и размера.Если вы вызываете subList для такого подсписка, вы получаете родительский указатель, указывающий на список, который сам имеет родительский указатель (и т.Если у вас очень глубокая иерархия родительских указателей, вы получаете StackOverflowError.

В следующем фрагменте показана изолированная проблема:

public static void main(String[] args) {
    List<String> lst = new ArrayList<String>();
    lst.add(""); 
    for (int i = 0; i < 50000; i++) {
        lst.set(0, "test");
        lst = lst.subList(0, 1);
    }

    lst.add("test2");       
}

Вывод: не используйте рекурсивный сублист, например:*

breadCrumbs = breadCrumbs.subList(0, breadCrumbs.indexOf(newViewID) + 1);

Вместо этого установите длину, удалив элементы с конца.

Более подробный анализ в моем блоге: http://programmingtipsandtraps.blogspot.com/2013/05/javautillistsublist-stackoverflowerror.html

0 голосов
/ 06 сентября 2011

Не думаю, что это из-за LinkedList. Я получил ту же ошибку при вызове subList для того же списка рекурсивно. Я думаю, что каждый раз, когда вызывается метод subList, его индексы начала / конца помещаются в стек. Если этот список огромен и, следовательно, слишком много раз вызывается этот метод, возникает StackOverFlowError.

0 голосов
/ 24 сентября 2010

Проблема была вызвана тем, что breadCrumbs были LinkedList - мы добавили слишком много элементов в LinkedList, и вызов subList выявил эту проблему.

0 голосов
/ 24 сентября 2010

Вот выдержка из соответствующего источника:

681    public ListIterator<E> listIterator(final int index) {
...
687        return new ListIterator<E>() {
688            private ListIterator<E> i = l.listIterator(index+offset);

Этот StackOverflowError указывает, что l как-то относится к текущему подсписку и таким образом вызывает свой собственный listIterator() в бесконечном цикле.

Откуда взялся breadCrumbs?Что говорит getClass()?

...