2017-07-20 10 views
5

Mam java.lang.OutOfMemoryError: Java heap space, gdy używam implementacji AbstractSpliterator, która zgłasza nieznany rozmiar.Implementacja AbstractSpliterator z nieznanymi rozmiarami wyrzuca OutOfMemoryError: Przestrzeń sterty Java

W tym przypadku zdefiniowałem klasę StreamCollapse, która rozszerza AbstractSpliterator i łączy serię sąsiednich elementów w implementacji tryAdvance(). Jego konstruktor nazywa super konstruktora jako super(Long.MAX_VALUE, source.characteristics()).

Jeśli chodzi o API documentation, oczekiwałem, że użycie Long.MAX_VALUE wskazuje nieznany rozmiar. Jednak wydaje się, że zamiast tego próbuje przydzielić pamięć o tym rozmiarze.

Dlaczego próbuje przydzielić to miejsce? Jaką wartość powinienem użyć dla szacowanego rozmiaru?

Tutaj jest przykład testu:

Stream<Integer> nrs = Stream.of(3, 3, 5, 5, 3, 3, 3, 4, 4, 4 ,5 , 5); 
Integer [] expected = {3, 5, 3, 4, 5}; 
Object[] actual = collapse(nrs).toArray(); 
assertEquals(actual, expected); 

i wdrożenie collapse() metoda:

static <T> Stream<T> collapse(Stream<T> source) { 
    return StreamSupport.stream(
      new StreamCollapse<T>(source.spliterator()), false); 
} 

class StreamCollapse<T> extends AbstractSpliterator<T> implements Consumer<T> { 

    private final Spliterator<T> source; 
    private T curr = null; 

    StreamCollapse(Spliterator<T> source) { 
     super(Long.MAX_VALUE, source.characteristics()); 
     this.source = source; 
    } 

    @Override 
    public boolean tryAdvance(Consumer<? super T> action) { 
     T prev = curr; 
     boolean hasNext; 
     while ((hasNext = source.tryAdvance(this)) && curr.equals(prev)) { } 
     if(hasNext) action.accept(curr); 
     return hasNext; 
    } 

    @Override 
    public void accept(T item) { 
     curr = item; 
    } 
} 

Odpowiedz

7

Należy usunąć właściwości z wmontował spliterator, na przykład:

// an unknown spliterator shouldn't having SIZED | SUBSIZED characteristics 
//            v 
super(Long.MAX_VALUE, source.characteristics() & (~(SIZED | SUBSIZED))); 

KIEDY a Spliteart lub jest używana przez Spliteartor, Spliterator#getExactSizeIfKnown przez strumień do utworzenia tablicy.

Characteristic value signifying that the value returned from estimateSize() prior to traversal or splitting represents a finite size that, in the absence of structural source modification, represents an exact count of the number of elements that would be encountered by a complete traversal.

IF wirowanie strumienia równolegle do Stream#toArray woli rzuca IllegalArgumentException jeśli estimateSize> = Long.MAX_VALUE - 8.

IF strumień jest sekwencyjnie strumieniowo Stream#toArray natomiast rośnie jego pojemności wewnętrznej tablicę do estimateSize.

+3

To jest poprawna odpowiedź, spliterator * musi * wyczyścić cechy 'SIZED' i' SUBSIZED'. Jako uzupełnienie, dobrym sposobem byłoby użycie 'estimateSize()' ze źródłowego spliteratora jako oszacowanego rozmiaru filtrującego spliteratora. W końcu rzeczywisty rozmiar będzie wynosił od zera do tego rozmiaru źródła. Tak właśnie działa "filter", a obecna implementacja poradzi sobie z tym znacznie lepiej niż z zupełnie nieznanymi rozmiarami. – Holger

+0

@Holger dziękuję za kontrolę mojej odpowiedzi. Dostaję również twoją sugestię. –

Powiązane problemy