Intended outcome:
Usage of reactive vars on the server-rendering shouldn't create a memory leak.
Actual outcome:
When an app, that uses reactive vars, is rendered on the server, it holds the query results in memory forever. Even though a new client, cache, and reactiveVar instances are created freshly for every request.
Probably because the references to reactive vars are held in a global context?
How to reproduce the issue:
We make use of the following function to create a new apollo client on every request to the serve:
export default function createCache() {
const reactiveVars = {
var1: makeVar({}),
var2: makeVar({}),
var2: makeVar({}),
};
return new InMemoryCache({
typePolicies: {
Query: {
fields: {
field1() {
return reactiveVars.var1();
},
field2() {
return reactiveVars.var2();
},
field3() {
return reactiveVars.var3();
},
},
},
},
});
}
And we observed from heap-dumps that the cache data is held in the memory when we use the reactive-vars even after a GC.
And if we remove the usage of reactive vars, the memory recovers back to normal after the GC.
Screenshot of a sample object(one of tons of similar ones) that were in memory:

Versions
System:
OS: macOS 10.15.7
Binaries:
Node: 12.13.0 - ~/.nvm/versions/node/v12.13.0/bin/node
Yarn: 1.18.0 - /usr/local/bin/yarn
npm: 6.12.0 - ~/.nvm/versions/node/v12.13.0/bin/npm
Browsers:
Chrome: 85.0.4183.121
Edge: 81.0.416.68
Firefox: 78.3.1
Safari: 14.0
npmPackages:
@apollo/client: ^3.2.5 => 3.2.5
@manojVivek Thanks for opening this issue! I can see what the problem is, and how to fix it, though I suspect any possible solution to this problem will depend on you explicitly calling client.stop() after you finish using client during SSR, which ultimately cancels all cache watches, which is an event we can use to remove the cache from the caches set for any reactive variables currently holding references to the cache. We're not currently hooking into that event (hence this bug), but I think it should be straightforward to set that up.
Most helpful comment
@manojVivek Thanks for opening this issue! I can see what the problem is, and how to fix it, though I suspect any possible solution to this problem will depend on you explicitly calling
client.stop()after you finish usingclientduring SSR, which ultimately cancels all cache watches, which is an event we can use to remove the cache from thecachesset for any reactive variables currently holding references to the cache. We're not currently hooking into that event (hence this bug), but I think it should be straightforward to set that up.