Intended outcome:
My app requires a lot of mutations, making small updates to the DB continuously. Just a simple mutation:
await client.mutate({
mutation: gql`
mutation {
${gqlStatements.join('')}
}
`
});
Actual outcome:
Everything functions fine, but the memory heap fills up with mutationString's that never seem to be collected.
How to reproduce the issue:
Simply run a much of simple mutations and check the heap. Here's a screenshop of Chrome Dev Tools:
https://imgur.com/a/zPTKM
Version
@Dygerati interesting! Would you be able to make a small reproduction of this using the apollo-error-template and maybe launchpad.graphql.com for a server?
Sure! Although I'm not really familiar with the react toolset, so I just mocked up a really simple vanilla JS example here:
https://github.com/Dygerati/apollo-memory-leak
I'm using the pad here:
https://launchpad.graphql.com/1xj5jr959
My github example will automatically create a heap snapshot in the directory every 10 minutes. After you let it run a bit, just load a couple snapshots into Chrome Dev Tools and set to compare. You should see a couple listings at the very top that are associated with Apollo--the one I sent a screenshot of earlier, as well as this one:
https://imgur.com/a/zun8z
Thanks!
Awesome! I'll take a look at it this week!
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions to Apollo Client!
Any updates on this?
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions to Apollo Client!
Thanks for reporting this @Dygerati. We've made several performance improvements to apollo-client since this issue was reported. Due to the age of this issue, I'm going to close it off, but if you're still encountering this problem with a more modern version of apollo-client (e.g. 2.3.2), please post back and let us know. Thanks!
Is this not just a memory leak by design? @hwillson what performance improvements are you referring to that would have solved this issue?
I haven't been using Apollo for very long but the behavior I see in my app is that when using link state a record of every mutation gets inserted into the cache under the ROOT_MUTATION key and seem to stay there indefinitely. Is there some process that is supposed to periodically clear out old mutations?
We just got bit by this is a bad way. I hope apollo3 has made huge improvements over apollo2 in this and other areas. Issues like this should make you think twice about using a library in production (especially the fact that it was never addressed, despite a very clear bug report with a repro attached).
I took a look at the apollo-client code (on 2.6.10). This infinitely growing mutationStore cache exists only to serve the devtools! It doesn't bother checking if we're in a production environment, or if the devtools exist. It just blindly stores every mutation, forever.
How many browsers in the world are using tons of extra memory because of this issue?
Here's a fix to disable mutation store. This still adds an entry for each mutation, so that if someone uses the devtools they'll get a message that the info has been removed by a monkey patch. You can just not store anything in initMutation if you want zero memory usage.
// APOLLO-MS-MONKEYPATCH
const mutationStore = apolloClient.queryManager.mutationStore;
const mutationStoreInitMutation: typeof mutationStore.initMutation = function(
this: any,
mutationId,
mutation,
variables
) {
this.store[mutationId] = {
mutation: 'removed, search for APOLLO-MS-MONKEYPATCH in the codebase',
variables: {},
loading: true,
error: null,
};
};
mutationStore.initMutation = mutationStoreInitMutation;
Note, you also need to pass fetchPolicy: 'no-cache' to client.mutate, because the standard InMemoryCache in apollo-client 2.6 also caches everything permanently. It even creates a new string containing all the variables and mutation string that are stored in mutationStore, for a double-whammy memory leak.
Most helpful comment
Sure! Although I'm not really familiar with the react toolset, so I just mocked up a really simple vanilla JS example here:
https://github.com/Dygerati/apollo-memory-leak
I'm using the pad here:
https://launchpad.graphql.com/1xj5jr959
My github example will automatically create a heap snapshot in the directory every 10 minutes. After you let it run a bit, just load a couple snapshots into Chrome Dev Tools and set to compare. You should see a couple listings at the very top that are associated with Apollo--the one I sent a screenshot of earlier, as well as this one:
https://imgur.com/a/zun8z
Thanks!