/* __ __ __ __ __ ___ * \ \ / / \ \ / / __/ * \ \/ / /\ \ \/ / / * \____/__/ \__\____/__/.ɪᴏ * ᶜᵒᵖʸʳᶦᵍʰᵗ ᵇʸ ᵛᵃᵛʳ ⁻ ˡᶦᶜᵉⁿˢᵉᵈ ᵘⁿᵈᵉʳ ᵗʰᵉ ᵃᵖᵃᶜʰᵉ ˡᶦᶜᵉⁿˢᵉ ᵛᵉʳˢᶦᵒⁿ ᵗʷᵒ ᵈᵒᵗ ᶻᵉʳᵒ */ package io.vavr; import io.vavr.collection.*; import org.openjdk.jol.info.GraphLayout; import java.text.DecimalFormat; import java.util.function.Predicate; import java.util.regex.Pattern; import static java.lang.Math.max; public class MemoryUsage { private static final DecimalFormat FORMAT = new DecimalFormat("#,##0"); private static Map<Integer, LinkedHashSet<Seq<CharSeq>>> memoryUsages = TreeMap.empty(); // if forked, this will be reset every time /** Calculate the occupied memory of different internals */ static void printAndReset() { for (Tuple2<Integer, LinkedHashSet<Seq<CharSeq>>> entry : memoryUsages) { final Seq<Integer> columnSizes = columnSizes(entry._1); System.out.println(String.format("\nfor `%d` elements", entry._1)); for (Seq<CharSeq> stats : entry._2) { final String format = String.format(" %s → %s bytes", stats.get(0).padTo(columnSizes.get(0), ' '), stats.get(1).leftPadTo(columnSizes.get(1), ' ') ); System.out.println(format); } } memoryUsages = memoryUsages.take(0); // reset } private static Seq<Integer> columnSizes(int size) { return memoryUsages.get(size) .map(rows -> rows.map(row -> row.map(CharSeq::length))).get() .reduce((row1, row2) -> row1.zip(row2).map(ts -> max(ts._1, ts._2))); } static void storeMemoryUsages(int elementCount, Object target) { memoryUsages = memoryUsages.put(elementCount, memoryUsages.get(elementCount).getOrElse(LinkedHashSet.empty()).add(Array.of( toHumanReadableName(target), toHumanReadableByteSize(target) ).map(CharSeq::of))); } private static String toHumanReadableByteSize(Object target) { return FORMAT.format(byteSize(target)); } private static long byteSize(Object target) { return GraphLayout.parseInstance(target).totalSize(); } private static HashMap<Predicate<String>, String> names = HashMap.ofEntries( Tuple.of("^java\\.", "Java mutable @ "), Tuple.of("^fj\\.", "Functional Java persistent @ "), Tuple.of("^org\\.pcollections", "PCollections persistent @ "), Tuple.of("^org\\.eclipse\\.collections", "Eclipse Collections persistent @ "), Tuple.of("^clojure\\.", "Clojure persistent @ "), Tuple.of("^scalaz\\.Heap", "Scalaz persistent @ "), Tuple.of("^scala\\.collection.immutable", "Scala persistent @ "), Tuple.of("^scala\\.collection.mutable", "Scala mutable @ "), Tuple.of("^io.vavr\\.", "Vavr persistent @ ") ).mapKeys(r -> Pattern.compile(r).asPredicate()); private static String toHumanReadableName(Object target) { final Class<?> type = target.getClass(); return prefix(type) + type.getSimpleName(); } private static String prefix(Class<?> type) { return names.find(p -> p._1.test(type.getName())).get()._2; } }