2a9a8c9f79ff4cdb7b1c73b50083d0ca8f7c6886
[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 = 1024 * 1024;
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 allow 1 second for it to complete;
79      * NB there is no guarantee when, or whether, it will run!
80      */
81     System.gc();
82     synchronized (this)
83     {
84       try
85       {
86         wait(1000);
87       } catch (InterruptedException e)
88       {
89       }
90     }
91
92     /*
93      * check used memory is 'reasonably low'
94      */
95     long availableMemory = Runtime.getRuntime().totalMemory() / ONE_MB;
96     long freeMemory = Runtime.getRuntime().freeMemory() / ONE_MB;
97     long usedMemory = availableMemory - freeMemory;
98     System.out.println("Memory in use after close all windows: "
99             + usedMemory + "MB");
100
101     /*
102      * if this assertion fails
103      * - set a breakpoint here
104      * - run jvisualvm to inspect a heap dump of Jalview
105      * - identify large objects in the heap and their referers
106      * - fix code as necessary to null the references on close
107      */
108     long expectedMax = 100L;
109     assertTrue(usedMemory < expectedMax,
110             String.format("Used memory %d > %d", usedMemory, expectedMax));
111   }
112
113   /**
114    * wait for consensus etc thread to complete
115    * 
116    * @param av
117    */
118   protected void waitForThreads(AlignViewport av)
119   {
120     while (av.isCalcInProgress())
121     {
122       try
123       {
124         Thread.sleep(200);
125       } catch (Exception x)
126       {
127       }
128     }
129   }
130
131   /**
132    * Generates an alignment (large enough for this test but not so large it is
133    * too slow or runs out of memory) and saves it in a temporary file.
134    * 
135    * @return
136    * @throws IOException
137    */
138   private File generateAlignment() throws IOException
139   {
140     File f = File.createTempFile("MemoryTest", "fa");
141     PrintStream ps = new PrintStream(f);
142     AlignmentGenerator ag = new AlignmentGenerator(false, ps);
143     ag.generate(1000, 20000, 0, 10, 15);
144     return f;
145   }
146 }