apollo-ios: App crashing because of high memory usage
Bug report
Hi there! As a follow up of another bug reported, @blizzd and I have gathered some info about the high memory usage when fetching the items.
Versions
- apollo-ios SDK version: 0.38.3
- Xcode version: 12.4
- Swift version: Swift 5
- Package manager: CocoaPods
Further details
Hi Apollo team!
I’m working on the integration of the Apollo client in our app, migrating from a networking layer that was based on “old fashion” POST requests. I’m facing some issues because the app is crashing because of the very high usage of the memory.
.Context.
Our app has to fetch from the server a few thousand elements. For several reasons, we had to split requests in bulks of 300. Thus, if the app needs to download 1500 items, it will create 5 separated requests that, afterwards, will be combined together with their output.
.Gist of the technical implementations.
It’s based on ReactiveSwift. Hopefully, even with little familiarity with it, this should be digestible by anyone.
let fetchingSignalProducers: Array<SignalProducer<[Item], NoError>> = ...
SignalProducer<[Item], RequestError>
.combineLatest(fetchingSignalProducers)
.map { arrayOfarrayOfItems in
...
}
Each one of the fetchingSignalProducers performs a fetch operation, running on a dedicated queue. The code above is running on a background, dedicated queue.
.Investigation.
We have been digging for a few days, using the Debug navigator
, the Debug Memory Graph
and the instruments.
These screenshots are from a run of the app stopped at a quite low level of usage compared to those that get to ~2GB.
From our investigation, it seems like the issue is whit this Array of PossiblyDeferred that creates a reference cycle.
Which other info can we provide for helping to fix this behaviour?
About this issue
- Original URL
- State: open
- Created 3 years ago
- Reactions: 1
- Comments: 26 (12 by maintainers)
Hi @designatednerd !
I hope to add some valuable insight in this. I may have found the reason why the memory does not get free. This also made me dive a bit deeper :
Now, it looks like your
Zip3Accumulator
which is usingGraphQLResultAccumulator
GraphQLResultAccumulator -> func zip<Accumulator1: GraphQLResultAccumulator, Accumulator2: GraphQLResultAccumulator, Accumulator3: GraphQLResultAccumulator>(_ accumulator1: Accumulator1, _ accumulator2: Accumulator2, _ accumulator3: Accumulator3) -> Zip3Accumulator<Accumulator1, Accumulator2, Accumulator3>
is using a protocol with anassociatedtype PartialResult
for it, which the function attempts to verify and accept results, but at the same time is allocating memory for each next result, while holding the previous result in memory. O( N x N ).https://stackoverflow.com/questions/44765347/does-enum-retain-its-associated-object
P.S. Experimenting with SQLStorage instead of In-Memory Storage only delayed the above effect.
Thanks for that info @Elaz-viz! We’ll look into this!