Skip to content

Instantly share code, notes, and snippets.

@devinrsmith
Last active August 29, 2015 14:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save devinrsmith/121d9a5ebd460c3bbaa0 to your computer and use it in GitHub Desktop.
Save devinrsmith/121d9a5ebd460c3bbaa0 to your computer and use it in GitHub Desktop.
Guava Concat Issue
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);
}
}
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));
}
}
@devinrsmith
Copy link
Author

Easy to get guava to fail with vm settings -Xms32m -Xmx32m and program settings 22 true false

@devinrsmith
Copy link
Author

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