summaryrefslogtreecommitdiffstats
path: root/devtools/client/memory/test/browser/browser_memory_refresh_does_not_leak.js
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/client/memory/test/browser/browser_memory_refresh_does_not_leak.js')
-rw-r--r--devtools/client/memory/test/browser/browser_memory_refresh_does_not_leak.js139
1 files changed, 139 insertions, 0 deletions
diff --git a/devtools/client/memory/test/browser/browser_memory_refresh_does_not_leak.js b/devtools/client/memory/test/browser/browser_memory_refresh_does_not_leak.js
new file mode 100644
index 0000000000..e0ee1eee41
--- /dev/null
+++ b/devtools/client/memory/test/browser/browser_memory_refresh_does_not_leak.js
@@ -0,0 +1,139 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/* global ChromeUtils */
+
+// Test that refreshing the page with devtools open does not leak the old
+// windows from previous navigations.
+//
+// IF THIS TEST STARTS FAILING, YOU ARE LEAKING EVERY WINDOW EVER NAVIGATED TO
+// WHILE DEVTOOLS ARE OPEN! THIS IS NOT SPECIFIC TO THE MEMORY TOOL ONLY!
+
+"use strict";
+
+const {
+ getLabelAndShallowSize,
+} = require("resource://devtools/shared/heapsnapshot/DominatorTreeNode.js");
+
+const TEST_URL =
+ "http://example.com/browser/devtools/client/memory/test/browser/doc_empty.html";
+
+async function getWindowsInSnapshot(front) {
+ dumpn("Taking snapshot.");
+ const path = await front.saveHeapSnapshot();
+ dumpn("Took snapshot with path = " + path);
+ const snapshot = ChromeUtils.readHeapSnapshot(path);
+ dumpn("Read snapshot into memory, taking census.");
+ const report = snapshot.takeCensus({
+ breakdown: {
+ by: "objectClass",
+ then: { by: "bucket" },
+ other: { by: "count", count: true, bytes: false },
+ },
+ });
+ dumpn("Took census, window count = " + report.Window.count);
+ return report.Window;
+}
+
+const DESCRIPTION = {
+ by: "coarseType",
+ objects: {
+ by: "objectClass",
+ then: { by: "count", count: true, bytes: false },
+ other: { by: "count", count: true, bytes: false },
+ },
+ strings: { by: "count", count: true, bytes: false },
+ scripts: {
+ by: "internalType",
+ then: { by: "count", count: true, bytes: false },
+ },
+ other: {
+ by: "internalType",
+ then: { by: "count", count: true, bytes: false },
+ },
+};
+
+this.test = makeMemoryTest(TEST_URL, async function ({ tab, panel }) {
+ let front = panel.panelWin.gStore.getState().front;
+
+ const startWindows = await getWindowsInSnapshot(front);
+ dumpn(
+ "Initial windows found = " +
+ startWindows.map(w => "0x" + w.toString(16)).join(", ")
+ );
+ is(startWindows.length, 1);
+
+ await reloadBrowser();
+
+ // Update the front as we may have switched to a new target and a new memory front
+ front = panel.panelWin.gStore.getState().front;
+
+ const endWindows = await getWindowsInSnapshot(front);
+ is(endWindows.length, 1);
+
+ if (endWindows.length === 1) {
+ return;
+ }
+
+ dumpn("Test failed, diagnosing leaking windows.");
+ dumpn(
+ "(This may fail if a moving GC has relocated the initial Window objects.)"
+ );
+
+ dumpn("Taking full runtime snapshot.");
+ const path = await front.saveHeapSnapshot({ boundaries: { runtime: true } });
+ dumpn("Full runtime's snapshot path = " + path);
+
+ dumpn("Reading full runtime heap snapshot.");
+ const snapshot = ChromeUtils.readHeapSnapshot(path);
+ dumpn("Done reading full runtime heap snapshot.");
+
+ const dominatorTree = snapshot.computeDominatorTree();
+ const paths = snapshot.computeShortestPaths(
+ dominatorTree.root,
+ startWindows,
+ 50
+ );
+
+ for (let i = 0; i < startWindows.length; i++) {
+ dumpn(
+ "Shortest retaining paths for leaking Window 0x" +
+ startWindows[i].toString(16) +
+ " ========================="
+ );
+ let j = 0;
+ for (const retainingPath of paths.get(startWindows[i])) {
+ if (retainingPath.find(part => part.predecessor === startWindows[i])) {
+ // Skip paths that loop out from the target window and back to it again.
+ continue;
+ }
+
+ dumpn(
+ " Path #" +
+ ++j +
+ ": --------------------------------------------------------------------"
+ );
+ for (const part of retainingPath) {
+ const { label } = getLabelAndShallowSize(
+ part.predecessor,
+ snapshot,
+ DESCRIPTION
+ );
+ dumpn(
+ " 0x" +
+ part.predecessor.toString(16) +
+ " (" +
+ label.join(" > ") +
+ ")"
+ );
+ dumpn(" |");
+ dumpn(" " + part.edge);
+ dumpn(" |");
+ dumpn(" V");
+ }
+ dumpn(
+ " 0x" + startWindows[i].toString(16) + " (objects > Window)"
+ );
+ }
+ }
+});