The Tool Desk
Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Puppeteer crashes for different memory reasons, and the correct fix depends on which limit failed. A Node.js heap exhaustion, a Chrome renderer crash, a container cgroup kill, and a Docker /dev/shm failure can look similar from the outside. First identify the failing process and measure its memory; then cap concurrency, close every browser resource, size Docker correctly, and only change runtime limits when the measurements justify it.
Start by identifying the failed memory budget
Do not begin with --max-old-space-size or Chrome safety flags. Record the exact error and the process that emitted it. The phrase in the log usually narrows the search:
| Symptom | Likely budget | What to measure |
|---|---|---|
JavaScript heap out of memory |
Node/V8 heap | Node heap usage, RSS and garbage-collection trend |
ENOMEM while creating workers or processes |
Host or container process/memory allowance | Active workers, browser processes, cgroup events and RSS |
| Renderer crash, “page crashed” or browser disconnect | Chrome renderer/process memory, shared memory or a killed child | Chrome parent and renderer RSS, /dev/shm, process exits |
| Container exits with an OOM-kill event | Container cgroup limit | memory.current, memory.events and the container limit |
| Browser starts, then fails during screenshots/PDFs | Peak allocation or retained buffers | Concurrent pages, image/PDF buffer sizes and application references |
Capture a baseline during a reproducible failure. Log the number of browsers, contexts, pages and queued jobs; Node RSS and heap; Chrome parent and renderer RSS; container memory values; and /dev/shm usage. Puppeteer’s troubleshooting guidance specifically warns that automatic test-worker detection can exceed a container’s allowance and produce ENOMEM.
Bound every kind of concurrency
Limit test workers
Jest may detect CPUs on the whole machine rather than the smaller container allocation. Run fewer workers explicitly:
#1 Best Overall
- Disclaimer: Maximum Speed requires overclocking/PC BIOS adjustments. Maximum speed and performance depend on system components, including motherboard and CPU
- Hand-sorted memory chips ensure high performance with generous overclocking headroom
- VENGEANCE LPX is optimized for wide compatibility with the latest Intel and AMD DDR4 motherboards
- A low-profile height of just 34mm ensures that VENGEANCE LPX even fits in most small-form-factor builds
- A solid aluminum heatspreader efficiently dissipates heat from each module so that they consistently run at high clock speeds
npx jest --maxWorkers=2
Choose a number that fits measured peak memory, not the host CPU count. If two workers each launch several pages, the real concurrency is the product of those levels.
Queue application jobs
Use a semaphore or queue so an incoming burst cannot create unlimited pages. Count jobs, pages, contexts and browsers separately. A simple in-process limiter looks like this:
import puppeteer from 'puppeteer';
const limit = 2;
let active = 0;
const waiting = [];
function acquire() {
if (active < limit) { active++; return Promise.resolve(); }
return new Promise(resolve => waiting.push(resolve)).then(() => { active++; });
}
function release() {
active--;
const next = waiting.shift();
if (next) next();
}
async function runJob(url) {
await acquire();
let browser;
try {
browser = await puppeteer.launch({headless: true});
const page = await browser.newPage();
await page.goto(url, {waitUntil: 'networkidle2', timeout: 60000});
return await page.screenshot({type: 'png'});
} finally {
if (browser) await browser.close().catch(() => {});
release();
}
}
For higher throughput, keep a small browser pool, but still cap pages per browser and total jobs. A queue prevents a traffic spike from becoming a memory spike.
Close pages, contexts and browsers on every path
Leaks commonly come from an exception path that skips cleanup. Put each lifecycle in try/finally, set navigation and operation timeouts, and close a page before dropping its reference. If you use contexts, close them before the browser.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
async function capture(browser, url) {
const context = await browser.createBrowserContext();
const page = await context.newPage();
try {
await page.goto(url, {waitUntil: 'domcontentloaded', timeout: 45000});
return await page.pdf({format: 'A4', printBackground: true});
} finally {
await page.close().catch(() => {});
await context.close().catch(() => {});
}
}
Do not retain page objects, response bodies, screenshots or PDFs in global arrays. Stream or write large artifacts instead of keeping many binary buffers alive. Remove event listeners and request-interception handlers when a job ends.
Recycle wedged workers
Some workloads fragment or retain memory inside Chrome even after normal navigation. Recycle a browser after a defined number of jobs, after repeated renderer crashes, or when RSS remains above your ceiling after all pages close. Treat recycling as containment, not a substitute for finding a leak. A supervisor should terminate and replace a browser that stops responding, while the queue records the failed job for retry.
Measure Node and Chrome separately
Node metrics
setInterval(() => {
const m = process.memoryUsage();
console.log({rss: m.rss, heapUsed: m.heapUsed, heapTotal: m.heapTotal, external: m.external});
}, 10000);
A rising heapUsed after jobs finish suggests JavaScript retention. A high RSS with a stable heap can indicate native buffers, libraries, or Chrome launched as a child process; inspect Chrome independently.
Chrome process metrics
In a Linux container, sample the browser parent and renderer processes with your process monitor and record RSS over the same timeline as Node. Track the maximum, not just the idle value. Screenshots, PDFs, large pages, fonts, video and many simultaneous tabs create short-lived peaks that average metrics hide.
Do these 3 things before closing this tab:
1Clear out junk files and repair common Windows errors2Fix the driver behind crashes, sound loss and screen glitches3Repair Windows errors before they cause bigger problemsContainer metrics
cat /sys/fs/cgroup/memory.current
cat /sys/fs/cgroup/memory.events
df -h /dev/shm
ps -eo pid,ppid,rss,cmd --sort=-rss | head
On cgroup v1 systems, the equivalent files may be under /sys/fs/cgroup/memory/. An increasing oom or oom_kill counter confirms the container, not V8, enforced the failure.
Give Docker enough memory and shared memory
Use a suitable image and process init
Use the official Puppeteer image, or install all dependencies required by the Chrome for Testing build you run. Start the container with an init process so child processes are reaped correctly:
docker run --init --shm-size=1g --memory=2g my-puppeteer-image
The exact values must come from your measured peak workload. --init addresses process management; it does not increase memory.
Rank #2
- Disclaimer: Maximum Speed requires overclocking/PC BIOS adjustments. Maximum speed and performance depend on system components, including motherboard and CPU
- AMD EXPO & Intel XMP 3.0 Compatible Only: Dual memory profiles allow you to easily select optimized settings for your platform, whether you’re running an AMD or Intel processor
- Dynamic RGB Lighting: Individually addressable RGB lighting delivers vibrant effects through a sleek, understated panoramic diffuser
- Onboard Voltage Regulation: Onboard voltage regulation for reliable power at high frequencies
- Maximum Bandwidth and Tight Response Times: Optimized for peak performance on the latest AMD and Intel DDR5 motherboards
Size /dev/shm
Docker commonly provides a small shared-memory mount. Heavy pages can exhaust it even when the cgroup still has free RAM. Increase it with --shm-size, then verify usage inside the container. If your deployment cannot enlarge shared memory, use a documented Chrome configuration that avoids relying on the default mount, understanding that disabling safety mechanisms can reduce isolation and should not be your first response.
Check sandbox and writable paths
Sandboxed Chrome needs the required container capability. Prefer a correctly configured sandbox over running with --no-sandbox; the latter removes a security boundary and can conceal an image or permission problem. Ensure the profile, cache and temporary directories are writable and have enough space. Read-only or full filesystems can surface as browser failures that are mistaken for OOM.
Keep Puppeteer and Chrome for Testing aligned
Puppeteer downloads a compatible Chrome for Testing build by default. If you set executablePath to a system Chrome or Chromium, you take responsibility for pinning and testing that pair. Do not silently mix a Puppeteer release with an unrelated browser binary. Record both versions in CI logs and reproduce with the same pair locally.
The Puppeteer installation documentation lists approximate Chrome for Testing download sizes of 170 MB on macOS, 282 MB on Linux and 280 MB on Windows. Those are download footprints, not the runtime RAM requirement; reserve disk and image space separately from the memory budget.
Choose an operating model deliberately
| Model | Strength | Cost or risk |
|---|---|---|
| One long-lived browser | Lowest startup overhead | Leaks and fragmentation can accumulate; requires recycling policy |
| Recycled browsers | Contains gradual growth and wedged processes | More startup time and browser downloads/cache activity |
| Many pages in one browser | Efficient sharing of one browser process | Less fault isolation; renderer peaks can coincide |
| Separate contexts or browsers | Better isolation between jobs | Higher baseline memory and process count |
| Host execution | Usually more available memory and simpler diagnostics | Less reproducible than a pinned container |
| Docker/CI | Repeatable limits and environments | Must budget cgroups, /dev/shm, init and permissions |
Start with the smallest concurrency that meets your latency target. Increase one dimension at a time while watching peak RSS and cgroup events.
Quick wins for a faster PC:
Scan for outdated or missing drivers - takes under a minuteDriver Scan →Repair Windows errors before they cause bigger problemsFix Now →Reduce peak work before raising limits
- Block unnecessary ads, trackers, fonts or media when they are not part of the test.
- Capture one element instead of a full page when the requirement allows it.
- Avoid loading many full-page screenshots or PDFs into memory simultaneously; write each result before starting the next.
- Use realistic navigation and selector timeouts so failed sites do not occupy workers indefinitely.
- Disable extensions and request interception rules that retain response bodies unless they are required.
- Investigate pages with infinite scrolling, canvas-heavy dashboards, large images or WebAssembly as separate workload classes.
Only after reducing avoidable peaks should you consider increasing the container memory or Node heap. A larger heap can postpone a crash while allowing an unbounded queue to consume the host.
When increasing Node’s heap is appropriate
--max-old-space-size controls V8’s old-generation heap; it does not enlarge Chrome’s renderer budget, Docker shared memory or the cgroup limit. Use it only when Node metrics show a legitimate JavaScript heap requirement and the container has matching headroom:
node --max-old-space-size=2048 worker.js
After changing it, repeat the same workload and verify that RSS, Chrome processes and cgroup usage remain within limits. If the error is a renderer crash or container OOM kill, this flag is the wrong fix.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Systematic troubleshooting
“JavaScript heap out of memory”
Find retained arrays, page data, response bodies and screenshot/PDF buffers. Add heap snapshots or allocation sampling around one job, close resources in finally, and lower concurrency. Raise the heap only when the retained data is intentional and bounded.
Recommended Free Tools
ENOMEM when Jest starts
Automatic worker detection may see all host CPUs while the container allows only a few processes. Set --maxWorkers explicitly, then reduce application-level browser concurrency as well.
Renderer crash or browser disconnect
Check renderer RSS, /dev/shm, cgroup events and the browser/Chrome pair. Increase shared memory or container memory based on measurements, split unusually large pages, and recycle the browser after repeated failures.
Rank #3
- Boosts System Performance: 32GB DDR5 RAM laptop memory kit (2x16GB) that operates at 5600MHz, 5200MHz, or 4800MHz to improve multitasking and system responsiveness for smoother performance
- Accelerated gaming performance: Every millisecond gained in fast-paced gameplay counts—power through heavy workloads and benefit from versatile downclocking and higher frame rates
- Optimized DDR5 compatibility: Best for 12th Gen Intel Core and AMD Ryzen 7000 Series processors — Intel XMP 3.0 and AMD EXPO also supported on the same RAM module
- Trusted Micron Quality: Backed by 42 years of memory expertise, this DDR5 RAM is rigorously tested at both component and module levels, ensuring top performance and reliability
- ECC Type = Non-ECC, Form Factor = SODIMM, Pin Count = 262-Pin, PC Speed = PC5-44800, Voltage = 1.1V, Rank And Configuration = 1Rx8
Container is killed without a Node exception
Inspect memory.events and the orchestrator’s termination reason. Lower concurrent jobs or increase the cgroup limit; a Node heap flag cannot override a cgroup kill.
Works locally but fails in CI
Compare memory limits, shared-memory size, filesystem permissions, sandbox capability, init process, CPU count and browser versions. Pin the image and browser, and log these values at startup.
Pages close but memory never falls
Determine whether Node RSS, Chrome RSS or file cache is retaining it. Run one URL at a time, remove extensions and interception, test without screenshots/PDFs, and bisect the page workload. If Chrome remains high after cleanup, recycle it and isolate the triggering site or feature.
Or skip the browser setup
For simple website screenshots, ScreenshotNeo provides a single HTTP request instead of maintaining Puppeteer, Chrome processes and Docker limits. Before capture it accepts cookie/consent banners and removes more than 60 known consent platforms, newsletter popups and chat widgets; each cleanup step can be disabled. Bot checks/CAPTCHAs, blank pages, timeouts, failed loads and cache hits are not billed, and response headers identify the page verdict and whether it was billed. It also offers an MCP server for Claude, Cursor and other MCP clients, with take_screenshot, get_page_info and capture_pdf tools.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
See the ScreenshotNeo API documentation for the full option set. The service supports full-page captures with lazy images loaded, CSS-selector element shots, dark mode, 12 device presets or custom viewports, retina scale, PDF paper size/margins/orientation/page ranges, HTML/CSS-to-image, custom JavaScript and CSS, clicks, hidden selectors, selector/delay/network-idle waits, request/resource blocking, headers, cookies, user agents, Authorization, timezone, geolocation, transparent backgrounds, resizing, chosen-TTL caching, signed image links, asynchronous jobs with signed webhooks, bulk capture of up to 100 URLs per call, usage data and an OpenAPI specification. Common screenshot-API parameter names also work, easing migrations.
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
Plans include 1,000 screenshots per month free with no card; paid plans start at $5 for 3,000 screenshots, and every feature is available on every plan. Create a free ScreenshotNeo account to try it.
FAQ
How do I know whether a crash is memory-related?
Correlate the timestamp with the exact error, process exit reason, RSS, cgroup events and /dev/shm usage. A browser disconnect alone is not proof of a Node heap failure.
Should I run one page per browser?
Not by default. Pages in one browser use fewer baseline resources, while separate browsers improve fault isolation. Measure both models with your actual pages and choose the smallest configuration that remains stable.
Does closing a page guarantee Chrome memory returns immediately?
No. Allocators, caches and fragmentation can keep RSS elevated. Track the trend after cleanup and use controlled browser recycling when memory does not return or a renderer repeatedly wedges.
Frequently Asked Questions
How do I know whether a crash is memory-related?
Correlate the timestamp with the exact error, process exit reason, RSS, cgroup events and /dev/shm usage. A browser disconnect alone is not proof of a Node heap failure.
Windows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallOutdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchShould I run one page per browser?
Not by default. Pages in one browser use fewer baseline resources, while separate browsers improve fault isolation. Measure both models with your actual pages and choose the smallest configuration that remains stable.
Does closing a page guarantee Chrome memory returns immediately?
No. Allocators, caches and fragmentation can keep RSS elevated. Track the trend after cleanup and use controlled browser recycling when memory does not return or a renderer repeatedly wedges.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




