Auditing Extension Impact with the Task Manager
Measure an MV3 extension's real memory and CPU cost with Chrome's Task Manager: reading per-extension rows, attributing content-script cost to tabs, spotting workers that never sleep, comparing builds, and Firefox's about:performance.
Table of Contents
A review says “this extension makes my browser slow”, and the team has no idea whether it is true. Profilers answer detailed questions about specific code, but the first question is simpler: how much memory and CPU does the extension use, in which processes, and does it go back to zero when idle? Chrome’s built-in Task Manager answers that in seconds, per extension, with no setup — and it is the same tool users open when they suspect an extension. Knowing how to read it, and how content-script cost hides inside tab rows, turns vague complaints into numbers you can track between releases. This guide shows how. It belongs to performance profiling and optimisation.
How extension cost appears in the Task Manager
Open it from the browser menu → More tools → Task Manager, or press Shift+Esc on Windows and ChromeOS (Search+Esc on ChromeOS). Each row is a task: tabs, the browser process, the GPU process, utility processes, and extensions. An extension’s service worker appears as a row named “Extension: Readable” while it is running and disappears when the worker stops; offscreen documents and extension pages opened in tabs appear as their own rows. Content scripts are different: they run inside the tab’s renderer process, so their memory and CPU are included in the tab’s row, not the extension’s. That is why an extension can look cheap in its own row while making every tab heavier.
Step-by-step: an extension impact audit
1. Add the right columns
Right-click a column header in the Task Manager and enable Memory footprint, CPU, JavaScript memory, Process ID and, if available, Idle wake ups. Memory footprint is the closest to what the operating system charges the process; JavaScript memory shows the V8 heap (with “live” in parentheses); idle wake-ups reveal timers and polling that keep waking the process.
2. Measure the idle baseline
1audit.md — idle baseline (clean profile, only this extension, 5 tabs of fixture pages)
2t+0 Extension: Readable footprint 38 MB CPU 0.0
3t+30 s Extension: Readable (row gone — worker stopped) ✓ worker sleeps
4Tabs article-1 … article-5 footprint 61–74 MB each
Execution context: a clean Chrome profile with only your extension. After a period without events, Chrome stops an idle extension service worker (about 30 seconds), and its row disappears. If the row stays with non-zero CPU, something keeps the worker awake — a setInterval, an open port, a long-running fetch, or frequent alarms. See reducing service worker cold-start latency for the other side of that trade-off.
3. Attribute content-script cost to tabs
1Compare (same fixture page, same profile, fresh tab each time):
2 extension disabled → tab footprint 61 MB, JS memory 9 MB
3 extension enabled → tab footprint 79 MB, JS memory 21 MB Δ ≈ 18 MB per tab
Execution context: manual measurement. Because content-script memory is folded into the tab, the only way to see it is to compare the same page with the extension disabled and enabled. Multiply the delta by the number of tabs a heavy user keeps open — 18 MB × 40 tabs is 720 MB, which users notice. Large deltas usually come from bundling big libraries into the content script, building big in-memory indexes per page, or leaking DOM references. See measuring content script impact on page load.
4. Watch for workers that never sleep
1// Common culprits in sw.js
2setInterval(poll, 10_000); // keeps the worker busy forever → use chrome.alarms
3const port = chrome.runtime.connect(...); // long-lived port from an always-open page
4chrome.alarms.create("tick", { periodInMinutes: 0.5 }); // wakes every 30 s → is this necessary?
Execution context: the service worker. Each of these keeps the worker running or waking constantly, which the Task Manager shows as a persistent row and idle wake-ups. Replace polling with events or longer alarms, and close ports when they are not needed. See throttling and debouncing high-frequency events.
5. Check memory growth over time
Leave a realistic session running — the side panel open, ten tabs with content scripts, normal use — and note JavaScript memory for the extension’s rows and the tabs every 15 minutes for an hour or two. Flat lines are healthy; steady growth in a side panel, offscreen document or tab suggests a leak worth profiling with heap snapshots. See profiling memory leaks in long-lived extension pages.
6. Record results per release
1perf-log.md
2| Version | Worker idle stops | Idle CPU | Tab Δ footprint | Side panel 1 h growth |
3|---------|-------------------|----------|-----------------|-----------------------|
4| 2.3.1 | yes (~30 s) | 0.0 | +6 MB | +2 MB |
5| 2.4.0 | yes (~30 s) | 0.0 | +18 MB ⚠ | +3 MB |
Execution context: the team’s release notes. A five-minute audit per release with the same fixture pages catches regressions — the jump in tab footprint here points straight at what changed in the content script for 2.4.0. Automating the same measurement with Playwright and CDP’s Performance.getMetrics is possible, but the manual check is a good start.
7. Use the same view as your users
When users report slowness, ask them to open the Task Manager, sort by memory footprint, and send a screenshot. It shows whether your extension’s rows (or the tabs it runs in) stand out, and often reveals that another extension or a heavy site is the real cause.
Common mistakes
- Only looking at the extension’s own row. Content-script cost is in the tabs.
- Measuring in a busy everyday profile. Other extensions muddy the numbers.
- One snapshot. Leaks show up only over time.
- Ignoring idle wake-ups. Polling drains laptops.
- Not comparing with the extension disabled. Deltas are what matter.
Cross-browser variation
- Chrome / Edge: Task Manager (Shift+Esc), per-extension rows; Edge also has a browser “Performance” panel with per-extension sleeping info.
- Firefox:
about:performancelists extensions with energy impact and memory, andabout:processesshows per-process CPU and memory including the extension process. - Safari: macOS Activity Monitor shows Safari web content processes; extension cost is harder to separate — compare with the extension disabled.
Verification
- Leave the extension idle and confirm its worker row disappears within about a minute.
- Measure the tab footprint delta with and without the extension on the same fixture page.
- Run a one-hour session and confirm JavaScript memory is flat.
- Record the numbers in the per-release log.
FAQ
Why does my extension’s row come and go?
That is the service worker starting for events and stopping when idle — the expected MV3 behaviour.
Is memory footprint or JavaScript memory more important?
Footprint is what the OS pays; JavaScript memory points at your heap. Watch both.
Can I read these numbers from code?
Not from extension APIs in stable Chrome. Use CDP in automated tests, or performance.measureUserAgentSpecificMemory() in cross-origin-isolated pages.
How many fixture tabs should the audit use?
Five to ten tabs with representative pages is enough to see per-tab deltas and multiply them out for heavy users.
Related
- Measuring content script impact on page load — the per-tab cost in depth.
- Profiling memory leaks in long-lived extension pages — when memory grows.
- Using Chrome internals pages for extensions — other diagnostic views.
- Performance profiling and optimisation — the parent topic.