package test.org.korsakow.media; import java.awt.Component; import java.awt.Dimension; import java.io.File; import java.lang.ref.WeakReference; import javax.swing.JFrame; import org.junit.After; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.korsakow.ide.resources.media.QTVideo; import org.korsakow.ide.util.StrongReference; import org.korsakow.ide.util.UIUtil; import quicktime.QTSession; import test.util.BaseTestCase; import test.util.MoreAsserts; import test.util.Unit; /** * This is a set of tests related to the performance of the QT api. * * Particular attention is paid to memory usage & deallocation. * * * @author d * */ @Ignore(value="Not accurate") public class TestQTMemory extends BaseTestCase { private static class MemoryRecord { public final long freeMemory; public final long totalMemory; public final long maxMemory; public MemoryRecord(long freeMemory, long totalMemory, long maxMemory) { this.freeMemory = freeMemory; this.totalMemory = totalMemory; this.maxMemory = maxMemory; } public MemoryRecord() { this(Runtime.getRuntime().freeMemory(), Runtime.getRuntime().totalMemory(), Runtime.getRuntime().maxMemory()); } public static MemoryRecord delta(MemoryRecord before, MemoryRecord after) { return new MemoryRecord(after.freeMemory-before.freeMemory, after.totalMemory-before.totalMemory, after.maxMemory-before.maxMemory); } } private final File base; private final File file; private final int N; private MemoryRecord memBefore; private MemoryRecord memAfter; private MemoryRecord memDelta; private final Unit unit; public TestQTMemory() { base = new File("resources/"); String filename = "v_divx_a_mp2.mov"; file = new File(base, filename); N = 100; unit = Unit.MegaBytes; } @Override @Before public void setUp() throws Exception { QTSession.open(); // printRecord("before", memBefore, unit); } @Override @After public void tearDown() throws Exception { QTSession.close(); } private static void printRecord(String prefix, MemoryRecord record, Unit unit) { System.out.printf("Memory %s%n", prefix); System.out.printf("\tfree: %2.2f%s%n", unit.convertBytes(record.freeMemory), unit.getPostfix()); System.out.printf("\ttotal: %2.2f%s%n", unit.convertBytes(record.totalMemory), unit.getPostfix()); System.out.printf("\tmax: %2.2f%s%n", unit.convertBytes(record.maxMemory), unit.getPostfix()); } private void commonBefore(String name) { System.out.println("Test: " + name); memBefore = new MemoryRecord(); printRecord("before", memBefore, unit); } private void commonAfter() { memAfter = new MemoryRecord(); printRecord("after", memAfter, unit); memDelta = MemoryRecord.delta(memBefore, memAfter); printRecord("delta", memDelta, unit); } /** * Tests that QT is releasing memory. * * We verify in two ways: * -first that you don't simply get an OutOfMemoryError * -more reliable: we verify that the amount of free memory remains stable over many iterations */ @Test public void testMemoryUsage() throws Throwable { commonBefore("Memory: remove first"); final StrongReference<Throwable> error = new StrongReference<Throwable>(); long referenceFreeMemory = 0; for (int i = 0; i < N; ++i) { final QTVideo video = new QTVideo(file.getAbsolutePath()); final WeakReference<Component> comp = new WeakReference<Component>(video.getComponent()); final JFrame frame = new JFrame(); UIUtil.runUITaskNow(new Runnable() { public void run() { frame.setSize(new Dimension(0, 0)); frame.setVisible(true); frame.add(comp.get()); } }); if (!error.isNull()) throw error.get(); UIUtil.runUITaskNow(new Runnable() { public void run() { try { frame.remove(comp.get()); } catch (Throwable t) { error.set(t); } } }); if (!error.isNull()) throw error.get(); video.dispose(); // it should not matter if we dispose the video or remove first frame.dispose(); long used = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory(); long free = Runtime.getRuntime().maxMemory() - used; if (i == 0) referenceFreeMemory = free; float percentFree = free/(float)Runtime.getRuntime().maxMemory(); // the tolerance is a twiddle value whose dependencies are the source movie and QTJava. // the point is basically to make sure that the amount of free memory is stable (ie no leaks) float tolerance = 1024*1024; MoreAsserts.assertEquals(free, referenceFreeMemory, tolerance); // System.out.println(i + "\t" + percentFree); // the free memory should remain relatively stable } commonAfter(); } }