-
Notifications
You must be signed in to change notification settings - Fork 25k
Description
Android has an event that is fired if memory is low:
https://developer.android.com/reference/android/content/ComponentCallbacks2.html#onTrimMemory(int)
React native is listening to it here:
Other code in react native can register to listen to the event. Currently, there is just one listener:
...that is registered from the CatalystInstance:
$ fgrep -ri handleMemoryPressure .
./ReactCommon/cxxreact/NativeToJsBridge.h: void handleMemoryPressure(int pressureLevel);
./ReactCommon/cxxreact/JSExecutor.h: virtual void handleMemoryPressure(__unused int pressureLevel) {}
./ReactCommon/cxxreact/NativeToJsBridge.cpp:void NativeToJsBridge::handleMemoryPressure(int pressureLevel) {
./ReactCommon/cxxreact/NativeToJsBridge.cpp: executor->handleMemoryPressure(pressureLevel);
./ReactCommon/cxxreact/Instance.h: void handleMemoryPressure(int pressureLevel);
./ReactCommon/cxxreact/Instance.cpp:void Instance::handleMemoryPressure(int pressureLevel) {
./ReactCommon/cxxreact/Instance.cpp: nativeToJsBridge_->handleMemoryPressure(pressureLevel);
./ReactAndroid/src/main/java/com/facebook/react/MemoryPressureRouter.java: // themselves in handleMemoryPressure()
./ReactAndroid/src/main/java/com/facebook/react/MemoryPressureRouter.java: listener.handleMemoryPressure(level);
./ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java: private native void jniHandleMemoryPressure(int level);
./ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java: public void handleMemoryPressure(int level) {
./ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java: jniHandleMemoryPressure(level);
./ReactAndroid/src/main/java/com/facebook/react/bridge/MemoryPressureListener.java: void handleMemoryPressure(int level);
./ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.h: void handleMemoryPressure(int pressureLevel);
./ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.cpp: makeNativeMethod("jniHandleMemoryPressure", CatalystInstanceImpl::handleMemoryPressure),
./ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.cpp:void CatalystInstanceImpl::handleMemoryPressure(int pressureLevel) {
./ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.cpp: instance_->handleMemoryPressure(pressureLevel);
The CatalystInstance implementation is:
This delegates the event via:
ReactCommon/cxxreact/Instance.cpp
ReactCommon/cxxreact/NativeToJsBridge.cpp
...finally calling:
https://github.com/facebook/react-native/blob/v0.61.5/ReactCommon/cxxreact/JSExecutor.h#L106
virtual void handleMemoryPressure(__unused int pressureLevel) {}
I don't see anything overriding this in the react-native, hermes, https://www.npmjs.com/package/jsc-android or JavaScriptCore repos, so (just from this code inspection) it looks like the onTrimMemory() event is ignored.
I think it would be useful to connect it up to JavaScript garbage collection. E.g. it would stop garbage-collectable js blob handles from holding on to BlobModule.java HashMap entries and could avoid the java OutOfMemoryErrors that are theoretically still possible even after this fix:
Hermes has a method for triggering garbage collection:
https://github.com/facebook/hermes/blob/v0.2.1/API/hermes/hermes.cpp#L489
...implementing a collectGarbage() in the jsi API:
https://github.com/facebook/react-native/blob/v0.61.5/ReactCommon/jsi/jsi/instrumentation.h#L47
Would need to find a suitable onTrimMemory() level. Would maybe need to make sure that use correct thread to trigger garbage collection.
React Native version:
react: 16.9.0 => 16.9.0
react-native: 0.61.5 => 0.61.5