We're using `Iterator.duplicate` to iterate the dataset multiple times without calling `Iterator.toArray`. According to implementation of `duplicate`, it does consume more memory and generates more temporary objects. I didn't notice that before. But according to previous experiments, `duplicate` is much more GC-friendly than `toArray`. I think the reason is that the underlying implementation of the `mutable.Queue` used in `duplicate` is actually a `mutable.LinkedList`, which doesn't require large amount of *continuous* memory, and thus may trigger full-GC less frequently.

If my guess is right, instead of using `duplicate` maybe we can simply call `Iterator.toList` reduce full-GC frequency?