5

We have existing web test cases written in Java using selenium-chrome-driver. Now we want to check for browser memory leaks after those tests are performed.

Manually, I do it by using Chrome Dev Tools - memory tab. Take heap dump,before I start the test, perform tests and then again take heap dump. Compare those two heap dumps which gives heap delta.

I am not able to find selenium-chrome-dev-tools API using which I could start the Chrome Dev Tool memory profiler (and perhaps some other tools), run my WebDriver tests (instantiating a Chrome browser instance, manipulating DOM elements, etc.), and then stop the profiler, then inspect the profiler's results to see if there are any memory leaks.

Is this concept even feasible or am I way out to lunch? Why/why not?

On the other hand, I have came across https://github.com/samccone/drool using which, I could get this information, but issue with that is I will have to rewrite all my existing java selenium tests in javascript, unless there is I can integrate drool with existing selenium tests.

Please suggest.

Note: Similar question is already asked under Chrome Dev Tools API & Selenium WebDriver but I don't see much helpful answer yet, so re posting again with more details.

Sohan Soni
  • 1,207
  • 21
  • 35
  • 1
    Are your memory leak tests aimed towards a small or larger scale of application user load? I am used to testing for memory leaks using load and performance testing tools like Jmeter and Gatling. The resulting reports there can tell you a lot more on memory leaks based on the performance counters you monitor. – Ceesiebird Feb 15 '19 at 13:50
  • Questions asking us to recommend or find a book, tool, software library, tutorial or other off-site resource are off-topic for Stack Overflow as they tend to attract opinionated answers and spam. Instead, [describe the problem](https://meta.stackoverflow.com/questions/254393/what-exactly-is-a-recommendation-question) and what has been done so far to solve it. – JeffC Feb 15 '19 at 14:34
  • this sounds like an X-Y problem. – Corey Goldberg Feb 15 '19 at 17:20

2 Answers2

7

Selenium supports org.openqa.selenium.JavascriptExecutor. We can get the value of window.performance.memory.usedJSHeapSize at any stage during testing. Below is the code.

  public static void reportMemoryUsage(WebDriver webDriver, String message) {
    ((JavascriptExecutor) webDriver).executeScript("window.gc()");
    try {
        TimeUnit.SECONDS.sleep(2);
    } catch (InterruptedException e) {
        LOGGER.error(e.getLocalizedMessage());
    }
    Double usedJSHeapSize = (Double) ((JavascriptExecutor) webDriver)
            .executeScript("return window.performance.memory.usedJSHeapSize/1024/1024");
    LOGGER.info("Memory Usage at " + message + " - " + usedJSHeapSize + " MB ");
 }

Call this method from your test suite, one at beginning of the test and one at the end. Difference between two usedJSHeapSize values will give the memory leak.

I am forcing garbage collection before taking usedJSHeapSize, to make sure the there is no garbage information collected. To enable gc function on window, you will have to set the -js-flags=--expose-gc option.

ChromeOptions options = new ChromeOptions();
options.addArguments("-js-flags=--expose-gc");
WebDriver webDriver = new ChromeDriver(options);
Sohan Soni
  • 1,207
  • 21
  • 35
  • 1
    This works and really reduced the memory utilization in my case! – Shawn Mar 18 '20 at 23:32
  • I am glad to hear that – Sohan Soni Jul 07 '20 at 16:25
  • I am able to report on heap size, nicely now. But with chrome 92 and selenium 3.141.59 I cannot seem to force garbage collection. I added the chrome option argument to expose garbage collection, as indicated above, and called it using the suggested javascript ((JavascriptExecutor) webDriver).executeScript("window.gc()"); but the heap size just seem to keep growing. Any further suggestions? – JackhammersForWeeks Jun 17 '21 at 17:54
2

Since drool is open source, you could see their implementation at https://github.com/samccone/drool/blob/master/lib/index.js and do something similar in Java like that:

    ChromeOptions options = new ChromeOptions();

    // Enable performance logging
    LoggingPreferences logPrefs = new LoggingPreferences();
    logPrefs.enable(LogType.PERFORMANCE, Level.ALL);
    options.setCapability(CapabilityType.LOGGING_PREFS, logPrefs);

    // Enable timeline tracing
    Map<String, Object> chromeOptions = new HashMap<>();
    Map<String, String> perfLoggingPrefs = new HashMap<>();
    perfLoggingPrefs.put(
        "traceCategories", "v8,blink.console,disabled-by-default-devtools.timeline");
    chromeOptions.put("perfLoggingPrefs", perfLoggingPrefs);
    options.setCapability(ChromeOptions.CAPABILITY, chromeOptions);

    WebDriver driver = new ChromeDriver(options);

...

    LogEntries performanceLogsBefore = driver.manage().logs().get("performance");

...

    LogEntries performanceLogsAfter = driver.manage().logs().get("performance");


Then filter the performance logs for "V8.GCScavenger", "V8.GCIncrementalMarking", "MajorGC" and "MinorGC" entries.

Jens Dibbern
  • 1,434
  • 2
  • 13
  • 20
  • 1
    Thanks Jens for the suggestion, I found something simpler for this which I will be posting as an answer here. – Sohan Soni Feb 20 '19 at 10:07