mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Release cached images when image component gets recycled on iOS (#51493)
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/51493 Changelog: [IOS][FIXED] Don't retain cached images in state after `RCTImageComponentView` gets recycled Fixes https://github.com/facebook/react-native/issues/51198 Crosspost from the task comment: From what I've been able to figure out, it seems like the image shadow nodes (keeping the loaded image in state) are being kept in memory by shadow node reference wrappers. It doesn't seem strictly like a memory leak - manually triggering garbage collection causes those nodes to be deallocated, but since Hermes isn't aware of the memory they are retaining, I think, it doesn't trigger it automatically. This diff releases the image data when the observers are notified and adds a new (`Consumed`) status to signify that. Reviewed By: sammy-SC Differential Revision: D75137263 fbshipit-source-id: 97eda7e6d1ef5cd633c4a5a4c37babc5e08968fb
This commit is contained in:
committed by
Facebook GitHub Bot
parent
6747f2b118
commit
1d452b17bf
@@ -21,6 +21,7 @@ class ImageResponse final {
|
||||
Completed,
|
||||
Failed,
|
||||
Cancelled,
|
||||
Consumed,
|
||||
};
|
||||
|
||||
ImageResponse(std::shared_ptr<void> image, std::shared_ptr<void> metadata);
|
||||
|
||||
+15
-1
@@ -10,6 +10,7 @@
|
||||
#include <algorithm>
|
||||
|
||||
#include <react/debug/react_native_assert.h>
|
||||
#include <react/featureflags/ReactNativeFeatureFlags.h>
|
||||
|
||||
namespace facebook::react {
|
||||
|
||||
@@ -31,6 +32,7 @@ void ImageResponseObserverCoordinator::addObserver(
|
||||
case ImageResponse::Status::Completed: {
|
||||
auto imageData = imageData_;
|
||||
auto imageMetadata = imageMetadata_;
|
||||
consumeResponse();
|
||||
mutex_.unlock();
|
||||
observer.didReceiveImage(ImageResponse{imageData, imageMetadata});
|
||||
break;
|
||||
@@ -41,7 +43,8 @@ void ImageResponseObserverCoordinator::addObserver(
|
||||
observer.didReceiveFailure(ImageLoadError{imageErrorData});
|
||||
break;
|
||||
}
|
||||
case ImageResponse::Status::Cancelled: {
|
||||
case ImageResponse::Status::Cancelled:
|
||||
case ImageResponse::Status::Consumed: {
|
||||
observers_.push_back(&observer);
|
||||
status_ = ImageResponse::Status::Loading;
|
||||
mutex_.unlock();
|
||||
@@ -93,6 +96,9 @@ void ImageResponseObserverCoordinator::nativeImageResponseComplete(
|
||||
status_ == ImageResponse::Status::Cancelled);
|
||||
status_ = ImageResponse::Status::Completed;
|
||||
auto observers = observers_;
|
||||
if (!observers.empty()) {
|
||||
consumeResponse();
|
||||
}
|
||||
mutex_.unlock();
|
||||
|
||||
for (auto observer : observers) {
|
||||
@@ -116,4 +122,12 @@ void ImageResponseObserverCoordinator::nativeImageResponseFailed(
|
||||
}
|
||||
}
|
||||
|
||||
void ImageResponseObserverCoordinator::consumeResponse() const {
|
||||
if (ReactNativeFeatureFlags::releaseImageDataWhenConsumed()) {
|
||||
status_ = ImageResponse::Status::Consumed;
|
||||
imageData_.reset();
|
||||
imageMetadata_.reset();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace facebook::react
|
||||
|
||||
+5
@@ -61,6 +61,11 @@ class ImageResponseObserverCoordinator {
|
||||
void nativeImageResponseFailed(const ImageLoadError& loadError) const;
|
||||
|
||||
private:
|
||||
/*
|
||||
* Resets the cached image data pointers. Needs to be protected by mutex_.
|
||||
*/
|
||||
void consumeResponse() const;
|
||||
|
||||
/*
|
||||
* List of observers.
|
||||
* Mutable: protected by mutex_.
|
||||
|
||||
Reference in New Issue
Block a user