Would this cause Garbage Collection issues
-
09-09-2019 - |
Question
I wrote a little Linq like DSL on top of Google Collections
public class IterableQuery {
public static <T> Where<T> from(Iterable<T> originalCollection) {
return new Where<T>( Iterables.transform(originalCollection, IterableQuery.<T>SAME()));
}
private static <T> Function<T, T> SAME() {
return new Function<T, T>(){
public T apply(T arg0) {
return arg0;
}
};
}
public static class SelectOrderBy<T>{
private final Iterable<T> iterable;
public SelectOrderBy(Iterable<T> iteable) {
this.iterable = iteable;
}
public SelectOrderBy<T> orderyBy( Comparator<T> sort ){
Ordering.forComparator(sort).sort((List< ? extends T>) iterable);
return new SelectOrderBy<T>( iterable);
}
public <F> Iterable<F> select( Function<? super T,? extends F> function){
return Iterables.transform(iterable, function);
}
public Iterable<T> selectEveryThing( ){
return iterable;
}
}
public static class Where<T>{
private final Iterable<T> iterable;
public Where(Iterable<T> iterable) {
this.iterable = iterable;
}
public SelectOrderBy<T> where(Predicate<T> predicate) {
return new SelectOrderBy<T>( Iterables.filter(iterable, predicate));
}
}
}
so I could do query collections in a more concise readable way
Iterable<? extends NewOrder > currentlyAssigned =
IterableQuery.
from(orders).
where(placedInLast10Days).
orderBy(lastName).
select(orderToNewOrder);
I am concerned whether this approach will cause an explosion of mini objects and cause some Garbage Collection issues( or any other issues) ?
Solution
I believe Google Collections uses deferred execution for most of its Iterators. Deferred execution would minimize the number of intermediate objects created as it would eliminate most of the intermediate/temporary lists that could be created for each call (where, orderby, etc).
Basically, the each element returned by currentlyAssigned.iterator() isn't calculated until you call iterator.next(). Until then, your currentlyAssigned iterable is just a set of operations, nothing more.
Your only concern on the explosion of mini-objects if those objects last longer than the duration of a single element operation... peak memory usage could get quite big in that case and you could potentially run out of memory on very large lists or if you were converting objects (i.e. calling ToUpper() on all strings or something). This would only be the case if the result of where() was another list, then orderby() created another list, so on and so on.
As far as the GC handling many short lived objects, there's no problem. The modern Java garbage collector heavily optimized to handle that exact behavior.
OTHER TIPS
I think it depends on how transform behaves, if its like a lazy filter, i.e. you don't attach a reference to every result. then its more than OK object count wise. Garbage collection wise, you are not keeping any hidden references, once you lose the root reference the whole graph becomes unreachable and gets collected. way to go man this is really neat.
The garbage collector has special code for short-lived objects, and they are very very cheap to use. Basically once in a while all reachable young objects are marked and every other object is reclaimed in one swoop.