JAL-2727 alignment width and height tailored to this test
[jalview.git] / test / jalview / gui / FreeUpMemoryTest.java
1 package jalview.gui;
2
3 import static org.testng.Assert.assertTrue;
4
5 import jalview.analysis.AlignmentGenerator;
6 import jalview.bin.Cache;
7 import jalview.bin.Jalview;
8 import jalview.io.DataSourceType;
9 import jalview.io.FileLoader;
10
11 import java.io.File;
12 import java.io.IOException;
13 import java.io.PrintStream;
14
15 import org.testng.annotations.BeforeClass;
16 import org.testng.annotations.Test;
17
18 public class FreeUpMemoryTest
19 {
20   private static final int ONE_MB = 1000 * 1000;
21
22   /**
23    * Configure (read-only) Jalview property settings for test
24    */
25   @BeforeClass(alwaysRun = true)
26   public void setUp()
27   {
28     Jalview.main(new String[] { "-nonews", "-props",
29         "test/jalview/testProps.jvprops" });
30     Cache.applicationProperties.setProperty("SHOW_ANNOTATIONS",
31             Boolean.TRUE.toString());
32     Cache.applicationProperties.setProperty("SHOW_QUALITY",
33             Boolean.TRUE.toString());
34     Cache.applicationProperties.setProperty("SHOW_CONSERVATION",
35             Boolean.TRUE.toString());
36     Cache.applicationProperties.setProperty("SHOW_OCCUPANCY",
37             Boolean.TRUE.toString());
38     Cache.applicationProperties.setProperty("SHOW_IDENTITY",
39             Boolean.TRUE.toString());
40   }
41
42   /**
43    * A simple test that memory is released when all windows are closed.
44    * <ul>
45    * <li>generates a reasonably large alignment and loads it</li>
46    * <li>performs various operations on the alignment</li>
47    * <li>closes all windows</li>
48    * <li>requests garbage collection</li>
49    * <li>asserts that the remaining memory footprint (heap usage) is 'not large'
50    * </li>
51    * </ul>
52    * If the test fails, this suggests that a reference to some large object
53    * (perhaps the alignment data, or consensus profile) has failed to be garbage
54    * collected. If this is the case, the heap will need to be inspected manually
55    * (suggest using jvisualvm) in order to track down where large objects are
56    * still referenced. The code (for example AlignmentViewport.dispose()) should
57    * then be updated to ensure references to large objects are set to null when
58    * they are no longer required.
59    * 
60    * @throws IOException
61    */
62   @Test(groups = "Memory")
63   public void testFreeMemoryOnClose() throws IOException
64   {
65     File f = generateAlignment();
66     f.deleteOnExit();
67
68     /*
69      * load alignment, wait for consensus and other threads to complete
70      */
71     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(f.getPath(),
72             DataSourceType.FILE);
73     waitForThreads(af.getViewport());
74
75     af.closeMenuItem_actionPerformed(true);
76
77     /*
78      * request garbage collection and wait briefly for it to run;
79      * NB there is no guarantee when, or whether, it will do so
80      */
81     System.gc();
82     synchronized (this)
83     {
84       try
85       {
86         wait(10);
87       } catch (InterruptedException e)
88       {
89       }
90     }
91
92     /*
93      * a second gc() call should not be necessary - but it is!
94      * the test passes with it, and fails without it
95      */
96     System.gc();
97
98     /*
99      * check used memory is 'reasonably low'
100      */
101     long availableMemory = Runtime.getRuntime().totalMemory() / ONE_MB;
102     long freeMemory = Runtime.getRuntime().freeMemory() / ONE_MB;
103     long usedMemory = availableMemory - freeMemory;
104     System.out.println("Memory in use after close all windows: "
105             + usedMemory + "MB");
106
107     /*
108      * if this assertion fails
109      * - set a breakpoint here
110      * - run jvisualvm to inspect a heap dump of Jalview
111      * - identify large objects in the heap and their referers
112      * - fix code as necessary to null the references on close
113      */
114     long expectedMax = 30L; // typically reports around 25
115     assertTrue(usedMemory < expectedMax, String.format(
116             "Used memory %d should be less than %d", usedMemory,
117             expectedMax));
118   }
119
120   /**
121    * wait for consensus etc thread to complete
122    * 
123    * @param av
124    */
125   protected void waitForThreads(AlignViewport av)
126   {
127     while (av.isCalcInProgress())
128     {
129       try
130       {
131         Thread.sleep(200);
132       } catch (Exception x)
133       {
134       }
135     }
136   }
137
138   /**
139    * Generates an alignment and saves it in a temporary file, to be loaded by
140    * Jalview. We use a peptide alignment (so Conservation and Quality are
141    * calculated), which is wide enough to ensure Consensus, Conservation and
142    * Occupancy have a significant memory footprint (if not removed from the
143    * heap).
144    * 
145    * @return
146    * @throws IOException
147    */
148   private File generateAlignment() throws IOException
149   {
150     File f = File.createTempFile("MemoryTest", "fa");
151     PrintStream ps = new PrintStream(f);
152     AlignmentGenerator ag = new AlignmentGenerator(false, ps);
153     int width = 100000;
154     int height = 100;
155     ag.generate(width, height, 0, 10, 15);
156     return f;
157   }
158 }