Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Memory Leak in React Native demo app (RN <= 0.59) #178

Closed
mtvv opened this issue Dec 10, 2019 · 7 comments
Closed

Memory Leak in React Native demo app (RN <= 0.59) #178

mtvv opened this issue Dec 10, 2019 · 7 comments
Labels

Comments

@mtvv
Copy link

mtvv commented Dec 10, 2019

Describe the bug
In the process of debugging a memory leak and subsequent crash in our React Native app (iOS), I decided to try out the demo implementation and see if there would be a problem in this minimal setting. This issue is related to the problem mentioned in #146 it seems.
When trying to select and upload JPEG/PNG files using the demo app the following behaviour can be observed both using the XCode debugger or React Native Debugger/Perf Monitor in Expo:

  • After an image is selected using the image picker, memory consumption goes up by a significant amount (more than the compressed file size of a JPEG, about 50% of the size of an uncompressed JPEG)
  • starting the upload peaks the memory consumption even further (way above the file size of the file being transferred)
  • during upload memory consumption remains stable
  • after a successful upload, memory is reclaimed but not all the way back to the original level
  • this leads to the app running out of memory over time and crashing.

It is notable that, that the memory consumption after picking an image and during the upload is much higher than the file being transferred.
I tried creating a log in instruments (where the behaviour can be followed as well) however using instruments seems to lead to problems with the transfers resulting in timeouts for large files.

Any pointers/help would be very appreciated! Thanks in advance!

To Reproduce
Run the app using expo or eject the app and run it using XCode. Select and upload the files and watch the memory usage in XCode or Perf Monitor.
While this issue can be observed with files of any size, it is most prominent with large files.
I have compiled a selection of large JPEGs in order to make the issue easily visible.

Expected behavior

  • Memory footprint after uploading should match the original memory consumption (prior to using the image picker)

Current behavior
To better illustrate the situation, here is a log of memory footprint snapshot after triggering different events

  • app start: 60.5 MB

  • selected a 9.5 MB JPEG (43 MB uncompressed): 85.9 MB

  • started upload: 114 MB

  • upload completed: 99.8 MB

  • restarted upload: 128 MB

  • received "Reloading image" message: 143 MB
    "2019-12-10 14:22:27.764 [info][tid:main][RCTImageView.m:422] Reloading image file:///var/mobile/Containers/Data/Application/9FA540E3-0CD4-41D6-B5D7-E7C769960F69/Library/Caches/ImagePicker/EBDD4F4B-410C-48EB-ACF4-E70143724102.jpg as size {2964.5, 200}"

  • upload completed: 114 MB

  • restarted upload: 142 MB

  • upload complete: 130 MB

  • restarted upload: 157 MB

  • upload complete: 142 MB

  • (… rinse and repeat …): 199 MB

  • picked a 36MB JPEG (285 MB uncompressed): 377 MB

  • started upload: 456 MB

  • upload complete: 393 MB

  • restarted upload: 667 MB

  • upload complete 465 MB

  • restarted upload: 601 MB

  • upload complete: 536 MB

You get the idea… After enough tries the app crashes due to lack of memory.
Screenshot 2019-12-10 at 15 46 27

Setup details

  • Runtime environment: React Native (iOS)
  • Used tus-js-client version: 1.8.0
  • Used tus server software: N/A (using the https://master.tus.io/files/ endpoint)
@mtvv mtvv added the bug label Dec 10, 2019
@mtvv
Copy link
Author

mtvv commented Dec 12, 2019

Just a minor update – I decided to make sure, that it is not the image picker component leaking memory and just tried hardcoding the uri of an image in the startUpload method like so:

// const file = this.state.file;
const file = { height: 1389,
    uri: 'file:///var/mobile/Containers/Data/Application/32780A57-E5E4-44AA-B8BC-B3876F0B7115/Library/Caches/ImagePicker/FC8389B7-4AC4-44AF-B54C-8C7A00855DFB.jpg',
    type: 'image',
    width: 1125,
    cancelled: false 
};

I then tried uploading the file several times and got pretty much the same result – memory is not fully reclaimed after an upload.

Screenshot 2019-12-12 at 17 48 04

Any pointers, what I could try to solve the problem?

@Acconut
Copy link
Member

Acconut commented Dec 12, 2019

Hi @mtvv, I unfortunately don't have any tips on how to fix this. I have no iOS device to test this and I wasn't able to reproduce in my Android environment. @nikolaytsigvintsev mentioned in #146 that it might be a bug directly in the React Native runtime but this was never confirmed or denied.

Are you able to trace the memory allocations? For example, in Android Studio I am able to see which large memory allocations were made by which code. That would help us to know which component is actually responsible for the memory increase.

@mtvv
Copy link
Author

mtvv commented Dec 13, 2019

Hey @Acconut thanks for looking into this!

I've just tested and the same behaviour can be observed in the iOS simulator as well – having a large JPEG file dropped into the photo library definitely helps though.

Do you have any way to test this in the iOS simulator? If there is any information I can provide to help you diagnose the issue, I would be happy to.

I managed to create a log in Instruments (it seems to work better with simulator). In the current session I have uploaded the same file 9 times and here are the allocations which seem to exactly correspond to the uploads:

Screenshot 2019-12-13 at 11 50 48

I started searching for possible problems with RCTNetworkTask and found some issues which might apply here:
facebook/react-native#23801
facebook/react-native#24405

I am however pretty new to React Native and am not sure whether I am looking in the right direction here… It would be great, if somebody with more insight could help me out. Are there any other contributors here who might have more experience with RN on iOS?
If the issue is based in React Native, I would expect there should be more people affected, right?

Thanks in advance!

@mtvv mtvv changed the title Memory Leak in React Native demo app Memory Leak in React Native demo app (RN <= 0.59) Dec 13, 2019
@mtvv
Copy link
Author

mtvv commented Dec 13, 2019

Ok, after consulting the issues linked above, it seemed that the problem tied to a bug dealing with blobs was fixed in the React Native > 0.59 so I decided to try to update:

    "react": "16.9.0",
    "react-dom": "16.9.0",
    "react-native": "0.61.5",

also had to update the Podfile template to current version.

After building and running everything works as it should! So the memory leak problem seems to originate at a deeper level than tus-js-client and is fixed in the current version of RN.
Not sure about the other issues in #146 but at least that leaves fewer problems on the table.

Screenshot 2019-12-13 at 14 53 33

@Acconut
Copy link
Member

Acconut commented Dec 13, 2019

That's incredible, @mtvv! Thanks for sharing! Are there still memory issues left for you?

@mtvv
Copy link
Author

mtvv commented Dec 13, 2019

Well one of the obvious issues is that the file is still being loaded into memory prior to transfer, so for now that means it would be impossible to upload a file larger than the free memory.
I also have a problem with the chunkSize: 5 * 1024 * 1024, option, this leads to a crash after the first chunk, but I understand these are separate problems and should probably go into separate issues?

@Acconut
Copy link
Member

Acconut commented Dec 13, 2019

Yes, please open separate issues for these topics. Let's see what we can do...

@Acconut Acconut closed this as completed Apr 24, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants