/* * Copyright (C) 2000-2013 Heinz Max Kabutz * * See the NOTICE file distributed with this work for additional * information regarding copyright ownership. Heinz Max Kabutz licenses * this file to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may * obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.gs.collections.impl.memory; import java.text.NumberFormat; import com.gs.collections.api.block.function.Function0; import com.gs.collections.api.block.procedure.primitive.IntProcedure; import com.gs.collections.impl.list.Interval; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public final class MemoryTestBench { private static final Logger LOGGER = LoggerFactory.getLogger(MemoryTestBench.class); private static final GCAndSleepProcedure GC_AND_SLEEP_PROCEDURE = new GCAndSleepProcedure(); private static final Interval GC_INTERVAL = Interval.oneTo(20); private final Class<?> clazz; private final String suffix; private MemoryTestBench(Class<?> clazz, String suffix) { this.clazz = clazz; this.suffix = suffix; } public static MemoryTestBench on(Class<?> clazz) { return MemoryTestBench.on(clazz, ""); } public static MemoryTestBench on(Class<?> clazz, String suffix) { return new MemoryTestBench(clazz, suffix); } /** * From newsletter 193 * (http://www.javaspecialists.eu/archive/Issue193.html). Used * to estimate memory usage by objects. */ public long calculateMemoryUsage(Function0<?> factory) { // Clean the slate and prep this.forceGCAndSleepMultipleTimes(); Object container = factory.value(); if (!this.clazz.isInstance(container)) { throw new RuntimeException(container.getClass().getCanonicalName()); } long memory = this.currentUsedMemory(); //noinspection UnusedAssignment,ReuseOfLocalVariable container = null; this.forceGCAndSleepMultipleTimes(); // Calculate memory before creation long memory2 = this.currentUsedMemory(); //noinspection UnusedAssignment,ReuseOfLocalVariable container = factory.value(); // Get rid of transient garbage this.forceGCAndSleepMultipleTimes(); // Calculate new used memory return this.currentUsedMemory() - memory2; } private long currentUsedMemory() { Runtime runtime = Runtime.getRuntime(); return runtime.totalMemory() - runtime.freeMemory(); } private void forceGCAndSleepMultipleTimes() { GC_INTERVAL.forEach(GC_AND_SLEEP_PROCEDURE); } public void printContainerMemoryUsage(String category, int size, Function0<?> factory) { String memoryUsedInBytes = NumberFormat.getInstance().format(this.calculateMemoryUsage(factory)); String sizeFormatted = NumberFormat.getInstance().format(size); LOGGER.info("{} {}{} size {} bytes {}", category, this.clazz.getName(), this.suffix, sizeFormatted, memoryUsedInBytes); } private static class GCAndSleepProcedure implements IntProcedure { @Override public void value(int each) { System.gc(); try { Thread.sleep(100); } catch (InterruptedException e) { throw new RuntimeException(e); } } } }