DEV Community

Cover image for Taming Browser RAM Bloat: Building a Zero-Dependency LRU Eviction Daemon in Python
Sukriti Chatterjee
Sukriti Chatterjee

Posted on

Taming Browser RAM Bloat: Building a Zero-Dependency LRU Eviction Daemon in Python

If your workstation sounds like an aircraft carrier prepping for launch every time you research a technical problem, you aren't alone.

Modern web browsers are resource-hungry. Keeping 40+ tabs open across multiple windows easily chews through 6GB to 10GB of RAM. While browser extensions like OneTab or The Great Suspender exist, they run inside the browser process itself. When the browser’s render thread freezes under heavy load, extensions often choke alongside it.

To solve this without bloating my setup, I built ZeroTab: an out-of-process, zero-dependency background daemon written in Python using asyncio and an $O(1)$ LRU (Least Recently Used) cache mechanic.

Here is how it works under the hood, why zero-dependency design matters for system daemons, and how you can reclaim gigabytes of memory with under 12MB of RAM overhead.


The Problem: The In-Process Suspension Trap

Most tab management utilities run as browser web extensions:

  1. They execute in sandbox threads inside the browser engine.
  2. They require extensive browser permissions ("read and change all your data on websites you visit").
  3. They must be installed and configured independently for every browser you use (Chrome, Edge, Brave, Safari).
  4. If a tab leaks memory or pegs the CPU at 100%, the extension runtime often fails to run its background eviction timers deterministically.

To get deterministic performance, we need to govern memory from the OS process level, completely decoupled from the browser's internal engine.


System Architecture: From 6.4 GB to 4.2 MB

ZeroTab acts as an external governor. It monitors tab access patterns, maintains an LRU eviction schedule, extracts the state of idle tabs, compresses that state to local storage, and replaces the tab with a lightweight local stub.

┌─────────────────────────────────┐
│     Active Browser Engine       │ (RAM: ~6.4 GB)
│  (Chrome / Safari / Edge / etc) │
└────────────────┬────────────────┘
                 │
                 ▼  Telemetric Polling (Async non-blocking)
┌─────────────────────────────────┐
│         ZeroTab Daemon          │ (RAM: <12 MB RSS)
│   - Python asyncio Event Loop   │
│   - O(1) LRU (Hash + DLL)       │
└────────────────┬────────────────┘
                 │
                 ▼  State Extraction & Eviction
┌─────────────────────────────────┐
│   JSON Gzip State Serializer    │
└────────────────┬────────────────┘
                 │
                 ▼  Lossless Compressed Disk Stub
┌─────────────────────────────────┐
│      Local Disk Storage         │ (Disk: ~4.2 MB)
└─────────────────────────────────┘

Enter fullscreen mode Exit fullscreen mode

Core Architecture Highlights

  • Zero Third-Party Dependencies: Built entirely with the Python 3.12+ standard library (asyncio, collections, gzip, json). You don't need a massive virtualenv or external C-extensions running in the background.
  • Minimal Footprint: Operates strictly within a <12MB RSS RAM ceiling. It never competes with your actual workloads (compilers, IDEs, Docker containers).
  • Deterministic $O(1)$ State Eviction: Tracking tab recency using naive array scans takes $O(N)$ time per cycle. ZeroTab uses a classic HashMap + Doubly-Linked List design to achieve constant-time $O(1)$ lookups, updates, and evictions.

Engineering Deep-Dive

1. Constant-Time $O(1)$ LRU Tab Eviction

To decide which tab to suspend, we track timestamps of user interactions. Whenever a tab is activated, it moves to the head of the list. When an eviction threshold is reached, the tail tab is evicted.

By combining an internal hash table for direct tab pointer lookup with a doubly-linked list for node ordering, both cache updates and eviction triggers operate at $O(1)$:

# Conceptual LRU Node representation
class TabNode:
    def __init__(self, tab_id: str, url: str, title: str):
        self.tab_id = tab_id
        self.url = url
        self.title = title
        self.prev = None
        self.next = None

# On Tab Access: Move node to Most-Recently-Used (Head) -> O(1)
# On Eviction Signal: Pop from Least-Recently-Used (Tail) -> O(1)

Enter fullscreen mode Exit fullscreen mode

2. Multi-Platform OS & Browser Interfacing

To avoid external dependencies like Selenium or Playwright, ZeroTab communicates with browsers via native OS capabilities:

  1. macOS Native (AppleScript / JXA): ZeroTab executes asynchronous AppleScript bridges via asyncio.create_subprocess_exec to query window and tab indices across Safari, Chrome, Edge, Brave, and Opera.
  2. Linux & Windows (Chrome Remote Debugging Protocol): For Chromium-based browsers on Linux and Windows, ZeroTab hooks into the Chrome DevTools Protocol (CDP) over native socket streams, reading metadata without third-party browser drivers.

3. Serialization & Memory Collapse

When a tab exceeds the timeout threshold (e.g., 300 seconds of inactivity):

  1. Its current URI, title, scroll offsets, and active state are captured.
  2. The payload is piped through Python’s native gzip and json serializers.
  3. The live tab renderer process is suspended or redirected to a lightweight local stub (about:blank or an offline stub UI).
  4. When the user returns to the tab, clicking anywhere triggers instant re-inflation from the local gzip state.

Getting Started with ZeroTab

Prerequisites

  • Python 3.12 or newer
  • Standard Terminal / Shell access

Installation

Clone the repository and install the daemon:

git clone https://github.com/SukritiC/ZeroTab.git
cd ZeroTab

# Optional: Set up an isolated environment
python3 -m venv .venv
source .venv/bin/activate

# Install the zero-dependency package
pip install .

Enter fullscreen mode Exit fullscreen mode

Running the Daemon

By default, ZeroTab runs in the foreground and outputs its eviction telemetry:

# Run against Safari with a 5-minute timeout and 5-second polling interval
python3 -m zerotab.main --browser safari --timeout 300 --poll 5

# Run against Google Chrome with a 30-second aggressive idle timeout
python3 -m zerotab.main --browser chrome --timeout 30

Enter fullscreen mode Exit fullscreen mode

Cross-Platform Setup (Chromium on Linux & Windows)

For Linux and Windows, start your Chromium browser with remote debugging enabled:

# Linux
google-chrome --remote-debugging-port=9222 &

# Windows (Command Prompt / PowerShell)
chrome.exe --remote-debugging-port=9222

Enter fullscreen mode Exit fullscreen mode

Then attach the ZeroTab daemon:

python3 -m zerotab.main --browser chrome --timeout 60

Enter fullscreen mode Exit fullscreen mode

Running the Unit Test Suite

Because the project relies purely on standard library tooling, running tests requires zero external runners:

python3 -m unittest discover tests/

Enter fullscreen mode Exit fullscreen mode

Benchmarks & Memory Impact

Testing across a session with 45 tabs open (including Google Docs, GitHub pull requests, YouTube, and StackOverflow):

Metric Without ZeroTab With ZeroTab Daemon Reduction
Browser RAM Footprint ~6,400 MB (6.4 GB) ~420 MB ~93% savings
ZeroTab Daemon Overhead N/A 11.2 MB RSS Negligible
Eviction Latency N/A < 1.2 ms ($O(1)$ hash pop) Real-time
Restoration Latency Full tab reload Instant (Local disk un-gzip) Minimal lag

Key Takeaways

  1. Out-of-Process is More Resilient: Background daemons running outside browser runtimes won't lock up when a browser window experiences thread lock.
  2. Standard Libraries are Underrated: Modern Python provides asyncio, collections, and gzip right out of the box. ZeroTab proves you do not need 50MB of third-party packages to write responsive, concurrent system tools.
  3. Data Structures Matter: Using an $O(1)$ HashMap + Doubly-Linked List structure keeps execution loops deterministic, even when scaling to hundreds of open tabs.

Links & Contributions

ZeroTab is open source. If you're interested in checking out the code, adding Firefox CDP socket support, or writing custom UI stubs, head over to GitHub:

👉 GitHub: SukritiC/ZeroTab

👉 Youtube: Technical Insights

Drop your questions, thoughts, or suggestions in the comments below!

Top comments (0)