Skip to content

InstantSearch.js refinementList Widget Leaks Memory #6669

@gkunesh

Description

@gkunesh

🐛 Current behavior

A circular/recursive reference is created by the createURL and searchForItems functions in the refinementList connector which are passed to the refinementList render function. This causes all past search states and hits to be retained in memory and increases the depth on every search.

🔍 Steps to reproduce

  1. Go to the InstantSearch.js template sandbox
  2. Open in new tab
  3. Open devtools and go to the memory tab
  4. Do anything that executes a search several times.
  5. Click the "Collect Garbage" button in devtools
  6. Select profiling type "Heap Snapshot"
  7. Click the "Take Snapshot" button
  8. Sort by Retained Size descending
  9. Expand the list of {instantsearch} objects. It should be near the top when sorted by retained size if enough searches were executed.
  10. Select an {instantsearch} object to see it in the Retainers section. Pick one with a high distance.
  11. In the expanded objects in the retainers section note multiple instances of createURL and searchForItems
  12. Hover over refinementList to see its retaining objects. If you do this for refinementList at multiple distances you will note that the retaining object "hits" has different values at different distances indicating that all search results have been retained in memory since the search app was started.

Google Drive Video since the file was rather large.

Live reproduction

https://codesandbox.io/s/github/algolia/instantsearch/tree/templates/instantsearch.js

💭 Expected behavior

In the case that these circular/recursive references to past searches and states is necessary, expected behavior would be to limit them so that only a certain number is retained. Otherwise, I believe expected behavior would be to somehow limit the context that createURL and searchForItems have access to so that they don't retain large objects like previous search states and results.

In my own app, instead of writing a new connector, I used a workaround. In the last widget to be rendered I added instantSearchInstance.renderState.MyIndex.refinementList = null; to the end of the custom render function. I expect this is a bad solution and might break things, but it seems to have done the trick in my case.

Package version

instantsearch.js 4.79.1

Operating system

Windows 11

Browser

Chrome Version 138.0.7204.101 (Official Build) (64-bit)

Code of Conduct

  • I agree to follow this project's Code of Conduct

Metadata

Metadata

Assignees

No one assigned

    Labels

    triageIssues to be categorized by the team

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions