Skip to content

Commit 81e47af

Browse files
giantslogikfacebook-github-bot
authored andcommitted
fix performance and memory usage of creating blob on Android (facebook#50121)
Summary: This PR fixes facebook#48657 - Memory usage for creating a blob lowered from _( nearest 2^N greater than the file size)+1KB_ previously To _(file size)+1KB_. This is achieved by avoiding internal calls to java.io.ByteArrayOutputStream.ensureCapacity by creating a buffer based on file size. - Increases the max file size a Blob can be created from before hitting a OutOfMemoryException. - Major performance increase by avoiding buffer copying ## Changelog: [ANDROID] [CHANGED] - Speed and Memory usage improvements to Android Blob support [ANDROID] [FIXED] - Creating of Blobs from large files now works. File size can now be upto available (free) heap size. Pull Request resolved: facebook#50121 Test Plan: Used the App here to test Android Blob creation. https://github.com/giantslogik/blob-large-file-fetch. Reviewed By: cortinico Differential Revision: D71464835 Pulled By: javache fbshipit-source-id: 38de7d83bcaee265fc6e7183f6b1160027cd4cb2
1 parent fd1e57b commit 81e47af

File tree

1 file changed

+33
-7
lines changed
  • packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/blob

1 file changed

+33
-7
lines changed

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -231,14 +231,40 @@ private byte[] getBytesFromUri(Uri contentUri) throws IOException {
231231
throw new FileNotFoundException("File not found for " + contentUri);
232232
}
233233

234-
ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream();
235-
int bufferSize = 1024;
236-
byte[] buffer = new byte[bufferSize];
237-
int len;
238-
while ((len = is.read(buffer)) != -1) {
239-
byteBuffer.write(buffer, 0, len);
234+
try {
235+
// Allocate a buffer upto the number of bytes that can be read without blocking
236+
// available() typically returns the file size if the uri represents an underlying file (i.e.
237+
// is instanceof FileInputStream)
238+
byte[] buffer =
239+
new byte
240+
[Math.max(
241+
1024,
242+
is.available())]; // fallback to 1024 if available returns 0 or a small size.
243+
int len;
244+
byte[] prevBuffer = new byte[1024];
245+
int prevLen = 0;
246+
247+
ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream();
248+
while ((len = is.read(buffer)) != -1) {
249+
// this performs a no-op on the first iteration of while. prevLen is zero
250+
byteBuffer.write(prevBuffer, 0, prevLen);
251+
// swap buffers.
252+
byte[] temp = prevBuffer;
253+
prevBuffer = buffer;
254+
buffer = temp;
255+
// set prevLen = length of data in prevBuffer
256+
prevLen = len;
257+
}
258+
259+
if (byteBuffer.size() == 0 && prevBuffer.length == prevLen) {
260+
// If EOF AND prevBuffer contains entire stream avoid using ByteArrayOutputStream
261+
return prevBuffer;
262+
}
263+
byteBuffer.write(prevBuffer, 0, prevLen);
264+
return byteBuffer.toByteArray();
265+
} finally {
266+
is.close();
240267
}
241-
return byteBuffer.toByteArray();
242268
}
243269

244270
private String getNameFromUri(Uri contentUri) {

0 commit comments

Comments
 (0)