Last active
August 29, 2015 14:17
-
-
Save devinrsmith/121d9a5ebd460c3bbaa0 to your computer and use it in GitHub Desktop.
Guava Concat Issue
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import com.google.common.base.Suppliers; | |
import com.google.common.collect.AbstractIterator; | |
import com.google.common.collect.Iterators; | |
import java.util.*; | |
import java.util.function.Consumer; | |
import java.util.function.Supplier; | |
/** | |
* Created by dsmith on 3/19/15. | |
*/ | |
public class GuavaConcatIssue { | |
public static class Node { | |
private final String current; | |
public Node(String current) { | |
this.current = current; | |
} | |
public Node left() { | |
return new Node(current + "L"); | |
} | |
public Node right() { | |
return new Node(current + "R"); | |
} | |
@Override | |
public String toString() { | |
return current; | |
} | |
} | |
public static class LazyIterator<T> implements Iterator<T> { | |
private final Supplier<Iterator<T>> supplier; | |
public LazyIterator(Supplier<Iterator<T>> supplier) { | |
this.supplier = Suppliers.memoize(supplier::get)::get; // wrap up guava supplier as java 8 supplier | |
} | |
public boolean hasNext() { | |
return supplier.get().hasNext(); | |
} | |
public T next() { | |
return supplier.get().next(); | |
} | |
} | |
public static Iterator<String> itInOrder(Node current, int depth, int maxDepth, boolean useGuavaConcat) { | |
// god i wish it was easier to do continuations, generators.... | |
// like python yield | |
final Iterator<String> left = depth < maxDepth ? | |
new LazyIterator<>(() -> itInOrder(current.left(), depth + 1, maxDepth, useGuavaConcat)) : | |
Collections.emptyIterator(); | |
final Iterator<String> us = Collections.singleton(current.toString()).iterator(); | |
final Iterator<String> right = depth < maxDepth ? | |
new LazyIterator<>(() -> itInOrder(current.right(), depth + 1, maxDepth, useGuavaConcat)) : | |
Collections.emptyIterator(); | |
// note: guava uses up too much memory b/c it's not allowing the past iterators to be GCd | |
// (due to ImmutableLists iterator!) | |
return useGuavaConcat ? Iterators.concat(left, us, right) : gcAbleConcat(left, us, right); | |
} | |
public static Iterator<String> gcAbleConcat(Iterator<String>... its) { | |
final Queue<Iterator<String>> queue = new LinkedList<>(Arrays.asList(its)); | |
return Iterators.concat(new AbstractIterator<Iterator<String>>() { | |
@Override | |
protected Iterator<String> computeNext() { | |
if (queue.isEmpty()) { | |
return endOfData(); | |
} | |
return queue.poll(); | |
} | |
}); | |
} | |
public static void main(String[] args) { | |
final int depth = Integer.parseInt(args[0]); | |
final boolean useGuavaConcat = Boolean.parseBoolean(args[1]); | |
final boolean print = Boolean.parseBoolean(args[2]); | |
final Consumer<String> consumer = print ? System.out::println : s -> {}; | |
itInOrder(new Node(""), 0, depth, useGuavaConcat).forEachRemaining(consumer); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import com.google.common.collect.AbstractIterator; | |
import com.google.common.collect.Iterators; | |
import java.util.*; | |
import java.util.stream.Stream; | |
/** | |
* Created by dsmith on 3/19/15. | |
*/ | |
public class GuavaConcatIssueBigObject { | |
public static <T> Iterator<T> gcAbleConcat(Iterator<T>... its) { | |
final Queue<Iterator<T>> queue = new LinkedList<>(Arrays.asList(its)); | |
return Iterators.concat(new AbstractIterator<Iterator<T>>() { | |
@Override | |
protected Iterator<T> computeNext() { | |
if (queue.isEmpty()) { | |
return endOfData(); | |
} | |
return queue.poll(); | |
} | |
}); | |
} | |
public static <T> Iterator<T> concat(boolean useGuava, Iterator<T>... its) { | |
return useGuava ? Iterators.concat(its) : gcAbleConcat(its); | |
} | |
public static class BigObject { | |
private byte[] bytes; | |
public void allocate(int bytes) { | |
this.bytes = new byte[bytes]; | |
} | |
} | |
public static void main(String[] args) { | |
final boolean useGuava = args.length == 0 || Boolean.parseBoolean(args[0]); | |
final long memory = Runtime.getRuntime().totalMemory(); | |
final int bigObjectBytes = (int)(memory / 10); | |
final int numBigObjects = 100; | |
concat(useGuava, (Iterator<BigObject>[]) Stream.generate(() -> Collections.singleton(new BigObject()).iterator()).limit(numBigObjects).toArray(Iterator[]::new)). | |
forEachRemaining(bo -> bo.allocate(bigObjectBytes)); | |
} | |
} |
For reference, here is the expected output for 4 true true
:
LLLL
LLL
LLLR
LL
LLRL
LLR
LLRR
L
LRLL
LRL
LRLR
LR
LRRL
LRR
LRRR
RLLL
RLL
RLLR
RL
RLRL
RLR
RLRR
R
RRLL
RRL
RRLR
RR
RRRL
RRR
RRRR
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Easy to get guava to fail with vm settings
-Xms32m -Xmx32m
and program settings22 true false