View Javadoc
1   /*
2    * Copyright (c) 2002-2025 Gargoyle Software Inc.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * https://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software
10   * distributed under the License is distributed on an "AS IS" BASIS,
11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12   * See the License for the specific language governing permissions and
13   * limitations under the License.
14   */
15  package org.htmlunit.javascript.background;
16  
17  import org.htmlunit.MockWebConnection;
18  import org.htmlunit.SimpleWebTestCase;
19  import org.htmlunit.WebClient;
20  import org.htmlunit.util.MemoryLeakDetector;
21  import org.junit.Test;
22  
23  /**
24   * <p>Tests for memory leaks. This test passes when run independently in Eclipse or via
25   * Maven (mvn test -Dtest=MemoryLeakTest), but not when all tests are run via Maven
26   * (mvn test). Note that this probably constitutes a false positive, meaning that the
27   * window isn't leaked in this situation -- we just can't get the JVM to GC it because
28   * there is no surefire way to force complete garbage collection.</p>
29   *
30   * <p>All suspected memory leaks should be verified with a profiler before a fix and/or
31   * unit test is committed. In JProfiler, for example, you can run a unit test and tell
32   * the profiler to keep the VM alive when it has finished running; once it has finished
33   * running you can go to the Heap Walker, take a snapshot of the heap, sort the resultant
34   * table by class name and find the class you're interested in, double-click on it, choose
35   * to view References to instances of this class, then right-click on the class and choose
36   * Show Paths to GC Root. This will give you a list of references which need to be
37   * eliminated. Once you have a fix, repeat the above steps in order to verify that the
38   * fix works.</p>
39   *
40   * @author Daniel Gredler
41   */
42  public class MemoryLeakTest extends SimpleWebTestCase {
43  
44      /**
45       * Empty test which keeps Maven/JUnit from complaining about a test class with no tests. This test
46       * class cannot be run automatically via Maven for the reasons outlined above.
47       * @throws Exception if an error occurs
48       */
49      @Test
50      public void leaks() throws Exception {
51          // windowLeaks();
52      }
53  
54      /**
55       * Verifies that windows don't get leaked, especially when there are long-running background JS tasks
56       * scheduled via <tt>setTimeout</tt> or <tt>setInterval</tt>. See the following bugs:
57       *    http://sourceforge.net/p/htmlunit/bugs/639/
58       *    http://sourceforge.net/p/htmlunit/bugs/648/
59       *
60       * @throws Exception if an error occurs
61       */
62      protected void windowLeaks() throws Exception {
63          final MemoryLeakDetector detector = new MemoryLeakDetector();
64  
65          try (WebClient client = new WebClient()) {
66              detector.register("w", client.getCurrentWindow());
67  
68              final MockWebConnection conn = new MockWebConnection();
69              conn.setResponse(URL_FIRST,
70                      DOCTYPE_HTML + "<html><body><script>setInterval('alert(1)',5000)</script></body></html>");
71              client.setWebConnection(conn);
72  
73              client.getPage(URL_FIRST);
74          }
75          assertTrue("Window can't be garbage collected.", detector.canBeGCed("w"));
76      }
77  
78  }