Skip to content

Commit

Permalink
fix fetch memory leak
Browse files Browse the repository at this point in the history
  • Loading branch information
huzhanbo1996 committed May 2, 2024
1 parent 0383669 commit d1c98dd
Show file tree
Hide file tree
Showing 7 changed files with 63 additions and 4 deletions.
6 changes: 4 additions & 2 deletions packages/react-native/Libraries/Blob/RCTBlobCollector.mm
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,10 @@
1,
[blobManager](jsi::Runtime &rt, const jsi::Value &thisVal, const jsi::Value *args, size_t count) {
auto blobId = args[0].asString(rt).utf8(rt);
auto blobCollector = std::make_shared<RCTBlobCollector>(blobManager, blobId);
return jsi::Object::createFromHostObject(rt, blobCollector);
auto blobCollector = std::make_shared<RCTBlobCollector>(blobManager, blobId);
auto blobCollectorJsObject = jsi::Object::createFromHostObject(rt, blobCollector);
blobCollectorJsObject.setExternalMemoryPressure(rt, [blobManager lengthOfBlobWithId:[NSString stringWithUTF8String:blobId.c_str()]]);
return blobCollectorJsObject;
}));
}
queue:RCTJSThread];
Expand Down
2 changes: 2 additions & 0 deletions packages/react-native/Libraries/Blob/RCTBlobManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ RCT_EXTERN void RCTEnableBlobManagerProcessingQueue(BOOL enabled);

- (void)store:(NSData *)data withId:(NSString *)blobId;

- (NSUInteger)lengthOfBlobWithId:(NSString *)blobId;

- (NSData *)resolve:(NSDictionary<NSString *, id> *)blob;

- (NSData *)resolve:(NSString *)blobId offset:(NSInteger)offset size:(NSInteger)size;
Expand Down
6 changes: 6 additions & 0 deletions packages/react-native/Libraries/Blob/RCTBlobManager.mm
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,12 @@ - (void)store:(NSData *)data withId:(NSString *)blobId
_blobs[blobId] = data;
}

- (NSUInteger)lengthOfBlobWithId:(NSString *)blobId
{
std::lock_guard<std::mutex> lock(_blobsMutex);
return _blobs[blobId].length;
}

- (NSData *)resolve:(NSDictionary<NSString *, id> *)blob
{
NSString *blobId = [RCTConvert NSString:blob[@"blobId"]];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,14 @@ public void store(byte[] data, String blobId) {
}
}

@DoNotStrip
public long getLengthOfBlob(String blobId) {
synchronized (mBlobs) {
byte[] data = mBlobs.get(blobId);
return data != null ? data.length : 0;
}
}

@DoNotStrip
public void remove(String blobId) {
synchronized (mBlobs) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,13 @@ BlobCollector::~BlobCollector() {
});
}

size_t BlobCollector::getBlobLength() {
static auto getLengthMethod = jni::findClassStatic(kBlobModuleJavaDescriptor)
->getMethod<jlong(jstring)>("getLengthOfBlob");
auto length = getLengthMethod(blobModule_, jni::make_jstring(blobId_).get());
return length;
}

void BlobCollector::nativeInstall(
jni::alias_ref<jclass>,
jni::alias_ref<jobject> blobModule,
Expand All @@ -53,7 +60,9 @@ void BlobCollector::nativeInstall(
auto blobId = args[0].asString(rt).utf8(rt);
auto blobCollector =
std::make_shared<BlobCollector>(blobModuleRef, blobId);
return jsi::Object::createFromHostObject(rt, blobCollector);
auto blobCollectorJsObject = jsi::Object::createFromHostObject(rt, blobCollector);
blobCollectorJsObject.setExternalMemoryPressure(rt, blobCollector->getBlobLength());
return blobCollectorJsObject;
}));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ class BlobCollector : public jni::HybridClass<BlobCollector>,
BlobCollector(jni::global_ref<jobject> blobModule, const std::string& blobId);
~BlobCollector();

size_t getBlobLength();

static constexpr auto kJavaDescriptor =
"Lcom/facebook/react/modules/blob/BlobCollector;";

Expand Down
32 changes: 31 additions & 1 deletion packages/rn-tester/js/examples/XHR/XHRExampleFetch.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,14 @@
'use strict';

const React = require('react');
const {Platform, StyleSheet, Text, TextInput, View} = require('react-native');
const {
Button,
Platform,
StyleSheet,
Text,
TextInput,
View,
} = require('react-native');

class XHRExampleFetch extends React.Component<any, any> {
responseURL: ?string;
Expand Down Expand Up @@ -59,6 +66,25 @@ class XHRExampleFetch extends React.Component<any, any> {
return responseHeaders;
}

startRepeatedlyFetch() {
const doRequest = () => {
const url =
'https://microsoftedge.github.io/Demos/json-dummy-data/5MB-min.json';
fetch(url, {
method: 'GET',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
})
.then(() => {
console.log('fetch one time');
})
.catch(error => console.error(error));
};
setInterval(doRequest, 500);
}

render(): React.Node {
const responseURL = this.responseURL ? (
<View style={{marginTop: 10}}>
Expand Down Expand Up @@ -88,6 +114,10 @@ class XHRExampleFetch extends React.Component<any, any> {

return (
<View>
<Button
title="RepeatedlyFetch"
onPress={() => this.startRepeatedlyFetch()}
/>
<Text style={styles.label}>Edit URL to submit:</Text>
<TextInput
returnKeyType="go"
Expand Down

0 comments on commit d1c98dd

Please sign in to comment.