Skip to content

Node lookups spike memory and the spike persists on JS-heavy pages (linkedin.com/in/<account>, behind login) #11

Description

@dashn9

Repeated node lookups against a logged-in linkedin.com/in/<account> push memory up sharply, and it does not come back down between lookups. Ordinary pages are fine; it shows on DOM-heavy, script-heavy ones.

Two things in the CDP lookup path look like they contribute.

1. DOM.getDocument on every locate

locate resolves the document root before every query:

https://github.com/dashn9/rustenium/blob/main/rustenium/src/conduit/cdp/adapter.rs#L316

let root_id = self.get_root_node_id().await?;
let cmd = QuerySelector::builder().node_id(root_id)...

Each DOM.getDocument makes Chrome's DOM agent mint and retain a fresh NodeId → backend-node mapping. That map is owned by the browser and is only dropped on document update or DOM.disable, so it grows per call and the growth is browser-side — which matches the spike persisting rather than being reclaimed when the DomNode goes out of scope on our side. locate_all and wait_for (which polls locate every 100ms) multiply it.

2. DescribeNode with depth(-1)

describe_by_id asks for the whole subtree:

https://github.com/dashn9/rustenium/blob/main/rustenium/src/conduit/cdp/adapter.rs#L305

DescribeNode::builder().node_id(node_id).depth(-1).build()

So matching a container selector on a LinkedIn profile serialises and deserialises that entire subtree into a DomNode tree, every time. Most callers want the node itself — its box, its attributes, its text — not its descendants.

Repro

  1. Open a logged-in linkedin.com/in/<account>.
  2. Loop locate on a container selector (or any wait_for, which polls it) a few hundred times.
  3. Watch RSS of the browser process and of the driving process. Both climb; neither returns to the baseline after the loop ends.

Suggested direction

  • Cache the document root per navigation instead of calling DOM.getDocument per lookup, and invalidate it on Page.frameNavigated / DOM.documentUpdated.
  • Take the depth as an option rather than hardcoding -1, defaulting to the node alone. A caller that wants a subtree can ask; today everyone pays for one.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions