Description
Description
We are developing an application using React Native and Expo. This application needs to run 24/7 and performs network requests using fetch()
regularly for monitoring purposes.
The issue we are facing is that after running the application for a while, from some point, network requests starting to fail. Through investigation using logs from Sentry, we have identified the following problem:
- We are using
fetch()
for network requests. - At the completion of a
fetch()
request, an error occurs:Property storage exceeds 196607 properties
.
The stack trace when this error occurs is as follows:
message: Property storage exceeds 196607 properties,
name: RangeError,
stack:
RangeError: Property storage exceeds 196607 properties
at register (/Users/expo/Library/Developer/Xcode/DerivedData/xxx/main.jsbundle:13781:20)
at createFromOptions (/Users/expo/Library/Developer/Xcode/DerivedData/xxx/main.jsbundle:13614:30)
at get (/Users/expo/Library/Developer/Xcode/DerivedData/xxx/main.jsbundle:13182:67)
at anonymous (/Users/expo/Library/Developer/Xcode/DerivedData/xxx/main.jsbundle:15155:45)
at call (native)
at dispatchEvent (/Users/expo/Library/Developer/Xcode/DerivedData/xxx/main.jsbundle:14686:31)
at setReadyState (/Users/expo/Library/Developer/Xcode/DerivedData/xxx/main.jsbundle:13481:31)
at __didCompleteResponse (/Users/expo/Library/Developer/Xcode/DerivedData/xxx/main.jsbundle:13289:29)
at apply (native)
at anonymous
Through further investigation, the following findings have been uncovered:
- The polyfill used for
fetch
, whatwg-fetch, returns responses asBlob
objects. - When a
Blob
is created, it is registered with blobID in the BlobRegistry, which is not automatically released. - This issue was previously reported in fetch() leaks memory on each request due to unreleased Blobs #19248 and was fixed by modifying whatwg-fetch. However, with the implementation of automatic garbage collection in [Blob] Release underlying resources when JS instance in GC'ed on iOS #24405, the implementation was reverted in commit bccc92d, returning to the original behavior.
- Although [Blob] Release underlying resources when JS instance in GC'ed on iOS #24405 enables
Blob
objects to be garbage collected, the Blob IDs registered in the BlobRegistry remain, causing the count to increase each timefetch
is called. - As a result, the
Property storage exceeds 196607 properties
error occurs
Our solution
To address this issue and prevent the error, we have modified the implementation of BlobRegistry
to use a Map
instead of an object. By using a Map, there is no limit to the number of entries.
const registry: Map<String, number> = new Map();
const register = (id: string) => {
const used = registry.get(id);
if (used != null) {
registry.set(id, used + 1);
} else {
registry.set(id, 1);
}
};
const unregister = (id: string) => {
const used = registry.get(id);
if (used != null) {
if (used <= 1) {
registry.delete(id);
} else {
registry.set(id, used - 1);
}
}
};
const has = (id: string): number | boolean => {
return registry.get(id) || false;
};
module.exports = {
register,
unregister,
has,
};
React Native Version
0.72.4
Output of npx react-native info
System:
OS: macOS 13.4.1
CPU: (8) arm64 Apple M2
Memory: 92.86 MB / 16.00 GB
Shell:
version: "5.9"
path: /bin/zsh
Binaries:
Node:
version: 18.17.0
path: /usr/local/bin/node
Yarn:
version: 1.22.19
path: /usr/local/bin/yarn
npm:
version: 9.6.7
path: /usr/local/bin/npm
Watchman: Not Found
Managers:
CocoaPods:
version: 1.12.1
path: /usr/local/bin/pod
SDKs:
iOS SDK:
Platforms:
- DriverKit 22.4
- iOS 16.4
- macOS 13.3
- tvOS 16.4
- watchOS 9.4
Android SDK: Not Found
IDEs:
Android Studio: 2021.2 AI-212.5712.43.2112.8815526
Xcode:
version: 14.3/14E222b
path: /usr/bin/xcodebuild
Languages:
Java: Not Found
Ruby:
version: 3.2.2
path: /Users/takanori.ishikawa/.rbenv/shims/ruby
npmPackages:
"@react-native-community/cli": Not Found
react:
installed: 18.2.0
wanted: 18.2.0
react-native:
installed: 0.72.4
wanted: 0.72.4
react-native-macos: Not Found
npmGlobalPackages:
"react-native": Not Found
Android:
hermesEnabled: Not found
newArchEnabled: Not found
iOS:
hermesEnabled: Not found
newArchEnabled: Not found
Steps to reproduce
Invoke fetch()
more than 196,607 times 😄
Snack, screenshot, or link to a repository
To demonstrate this issue, I created a simple Expo application.
https://github.com/ishikawa/react-native-fetch-property-storage-exceeds-error
You can run it with expo:
$ npm i
$ npm run ios