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

[Serious Bug] Android Image not render after a few times of uses #8677

Closed
narychen opened this issue Jul 10, 2016 · 90 comments
Closed

[Serious Bug] Android Image not render after a few times of uses #8677

narychen opened this issue Jul 10, 2016 · 90 comments
Labels
Help Wanted :octocat: Issues ideal for external contributors. Ran Commands One of our bots successfully processed a command. Resolution: Fixed A PR that fixes this issue has been merged. Resolution: Locked This issue was locked by the bot.

Comments

@narychen
Copy link
Contributor

narychen commented Jul 10, 2016

It's a serious problem since the early version and never being solved.
Reloading of JS will quickly lead to this bug but it will always happen whether or not you do the reloading.
When you use back button to quit the app on android and re-launch it, the image will still not show. I think it is because Fresco will not be closed after you quit. It is running as long as your phone is on until you remove your app from the task manager of android.
This means your app will not show image after a period of time even if it doesn't have a lot of image to show.
Please give a high priority to this problem because it will never be production ready for react-native of android if the image will go away after a few times of uses.

@fab1an
Copy link

fab1an commented Jul 11, 2016

I have never once experienced this bug.

Can you show a code-example where this happens?

@RooneyLeeSJ
Copy link

http://facebook.github.io/react-native/releases/0.26/docs/known-issues.html#memory-issues-with-png-images
It was reported in RN 0.26, but I found the issue has gone in RN 0.29. So I upgrade RN version to 0.29 but image issue that you described is still remained.
The file format most of images in my apps are png file. Do you think If I change image file format PNG to JPG, does it work well?

@narychen
Copy link
Contributor Author

@RooneyLeeSJ My image is all JPG, from the camera roll
It's due to a TooManyBitmapsException in fresco. Check this facebook/fresco#213
But it is still not working after clear the memory caches in Fresco

@narychen
Copy link
Contributor Author

I just want to build the Fresco from source into the react-native to debug the error. But I haven't found a way to build it with react-native. Can anyone give a suggestion?

@narychen
Copy link
Contributor Author

@fab1an Maybe you never once created an app that has many pictures to show.
check this issue #6649

@narychen
Copy link
Contributor Author

@fab1an I think the UIExplorer CameraRollExample could re-produce this problem if your mobile phone has many photos. Browse it and reload JS a few times, it may happen.

@charpeni
Copy link
Contributor

@narychen What version of React Native are you using?

To build React Native from source and setting up logcat you can follow these instructions : Build React Native from source & Investigating issues with logcat.

@ghost ghost added Android Ran Commands One of our bots successfully processed a command. labels Jul 11, 2016
@narychen
Copy link
Contributor Author

narychen commented Jul 11, 2016

@charpeni I have already built the ReactAndroid from source code.
I mean building fresco within ReactAndroid. I just tried it. it's really very complicated because fresco has many sub projects and android gradle cannot directly use the settings.gradle from fresco as gradle can only have a top level settings.gradle.

@narychen
Copy link
Contributor Author

narychen commented Jul 11, 2016

@charpeni The bug exists from the early version of 0.15 to 0.27.2 which I am using now.
I checked source code of 0.12 and it always used fresco, so I guessed that the problem accompanied with react-native from the old days.

@narychen
Copy link
Contributor Author

I hope someone responsible for the Image module of ReactAndroid in facebook could come out and fix it because it has existed for really a long time and never get any attention.
But the app will lose its users if it cannot show image any longer after a not so long time use.

@fab1an
Copy link

fab1an commented Jul 11, 2016

Can you reproduce this? Does using Fresco.shutDown() like described in #8518, help?

@charpeni
Copy link
Contributor

charpeni commented Jul 11, 2016

Are you up to provide an example project with the easy reproducible bug without dependancy to
the CameraRoll photos ?

@narychen
Copy link
Contributor Author

@fab1an I tried Fresco.shutDown() and imagePipeline.clearCaches(). It didn't work.
I checked the code of Fresco and didn't see any code decrease the mCount and mSize in com.facebook.imagepipeline.memory.BitmapCounter. The two property is the cause of the exception.

And further more the code of shutDown will call clearCaches but will not create a new imagepipeline if the old instance is not null. So call shutDown() will be the same with clearCaches()

@narychen
Copy link
Contributor Author

@charpeni When I first used react-native to create something half a year ago, I just noticed it will not render image after a few times of reloading. I didn't pay a lot of attention because I thought it may be a problem of reloading.
But now I find that the problem will still happen even if you don't reload the JS. JUST quit and launch and quit and launch repeat this action a few times. Your image will not render.
My android phone version is android 4.3 .

If you don't use CameraRoll, the image number will take a long time to accumulate to exceed the maxCount of fresco cache pool.

@narychen
Copy link
Contributor Author

Another issue I found #7408 caused by this bug.
So it is a bug easy to happen and reproduce.

@ms88privat
Copy link

+1, this is a very big problem.

@charpeni
Copy link
Contributor

@andreicoman11 Have you noticed this on Facebook's side?

@ghost ghost added Help Wanted :octocat: Issues ideal for external contributors. Ran Commands One of our bots successfully processed a command. labels Jul 11, 2016
@fab1an
Copy link

fab1an commented Jul 12, 2016

I think I have found the reason for this, see the mentioned bug: #8711

@sneerin
Copy link

sneerin commented Jul 12, 2016

also having this issue, this is very critical, list view with any image set is broken after few usages

@narychen
Copy link
Contributor Author

narychen commented Jul 13, 2016

I finally found something important.
I got a way to easily replace the repo Fresco with my own built one. Then I added a log in BitmapCounter.java of Fresco.

  public synchronized boolean increase(Bitmap bitmap) {
    final int bitmapSize = BitmapUtil.getSizeInBytes(bitmap);
    if (mCount >= mMaxCount || mSize + bitmapSize > mMaxSize) {
      return false;
    }
    mCount++;
    mSize += bitmapSize;
    Log.d("myfresco", "-"+mCount+"-"+mSize);  ///add this===>
    return true;
  }

Then I found the logging is weird.
mCount and mSize could raise up and down when you browse a lot of images.
It will never exceed the mMaxCount and mMaxSize.
But when I press backButton of my android phone or just reloading JS of react-native, the mCount and mSize will start raising up from the value at when you quit or reload.
So after a few times of quit/launch or reloading, the mSize or mCount will exceed the threshold.

Then I add a method in FrescoModule.java in ReactAndroid

  @ReactMethod
  public void clearCache() {
    ImagePipeline imagePipeline = Fresco.getImagePipeline();
    imagePipeline.clearCaches();
  }

And call it from JS side of react-native

    Platform.OS=='android' && BackAndroid.addEventListener('hardwareBackPress', ()=>{
        NativeModules.FrescoModule.clearCache();
        return false;
      }
    });

The quit behavior will not cause mSize and mCount to accumulate. It will always start counting from zero.
It seems that when you quit the app which uses Fresco without calling clearCache, it will leak.
The problem seems to be fixed as I just thought, but no, it's not.
The pictures do could show after a few times quit/launch. But then the App will suddenly crash down. I think the memory is not truly been released by Fresco clearCache. It just decrease the count. What is happened inside should be further explored.

@narychen
Copy link
Contributor Author

And add clearCache at the reloading point

    options.put(
        mApplicationContext.getString(R.string.catalyst_reloadjs), new DevOptionHandler() {
          @Override
          public void onOptionSelected() {
              ImagePipeline imagePipeline = Fresco.getImagePipeline();
              imagePipeline.clearCaches();
              handleReloadJS();
          }
        });

in DevSupportManagerImpl.java

The image not render problem could be solved.

But!!!!!! The Fresco leaking problem is still there, after a few times of reloading the App will crash.

@sneerin
Copy link

sneerin commented Jul 14, 2016

I'm considering to repace fresco, how to you think how hard it will be to implement?

@sneerin
Copy link

sneerin commented Jul 14, 2016

From my experience this https://github.com/bumptech/glide works way more stable a bit slower on low end devices but no memory leaks so far and what is more important it shows images all the time not only first 3 times.

@fab1an
Copy link

fab1an commented Jul 14, 2016

@sneerin If you want to support only modern devices, it's not hard to write an ImageLoader/Cache. If you do, give the CSP/Actor a model a try, so you won't get up in multithreading issues.

But keep in mind that Fresco has many many more features that would need a lot of time to replicate. So I think it's important that fresco, or whatever is causing these memory-issues get's fixed.

@oprisnik
Copy link
Contributor

Do you use a ScrollView? Or just simple <Image/>?

As @fab1an suggested, looking at heap dumps can give clues what is holding on to the bitmaps and how many bitmaps are still in memory.
Does this repro for you with the simple example that I've posted a while ago?

@narychen seems to be loading images from a camera roll. If you have for example a grid view of small thumbnails and you load all full resolution images, this will easily result in an OOM.
If you use a ScrollView, it's important that view recycling is turned on.

It would be great to have a simple way to repro this.

@sbycrosz
Copy link

Since most of the problems come from Fresco not properly releasing memory when ReactActivity is destroyed (via back button), would changing the behaviour of back button to not destroy the activity but to move it to background via moveTaskToBack solve most of the problem?

But ofc we'll need to trust android will kill the process when it needs more memory..

@narychen
Copy link
Contributor Author

narychen commented Oct 1, 2016

@oprisnik No. I'm building an IM app with cameraRoll. You could select picture from cameraRoll to send. And the app shows a lot of pictures which could be from network or local disk. And it will also show gif pictures, not only png.
Yes of course I'm using ScrollViews and ListViews. And load all full resolution images.

@narychen
Copy link
Contributor Author

narychen commented Oct 1, 2016

@oprisnik One more question how to turn on recycling of view when use a ScrollView.
I set removeClippedSubviews=true of ListView. Is it working?

@narychen
Copy link
Contributor Author

narychen commented Oct 1, 2016

I caught the crash exception info in Android monitor.

10-01 20:58:05.446 12594-12707/com.eggf V/unknown:NativeMemoryChunkPool: release (reuse) (object, size) = (43a2b350, 65536)
10-01 20:58:05.446 12594-12707/com.eggf V/unknown:NativeMemoryChunkPool: Used = (25, 6125568); Free = (8, 305152)
10-01 20:58:05.446 12594-12594/com.eggf V/unknown:AbstractDraweeController: controller 4372e8e0 1474: release: image: CloseableReference 4347a720
10-01 20:58:05.446 12594-12594/com.eggf V/unknown:AbstractDraweeController: controller 43b4ea88 1480: final_failed @ onFailure: failure: java.lang.RuntimeException: Failed to pin Bitmap
10-01 20:58:05.446 12594-12702/com.eggf E/CursorWindow: Could not create CursorWindow from Parcel due to error -12.
10-01 20:58:05.446 12594-12704/com.eggf E/CursorWindow: Could not create CursorWindow from Parcel due to error -12.
10-01 20:58:05.456 12594-12702/com.eggf E/CursorWindow: Could not create CursorWindow from Parcel due to error -12.
10-01 20:58:05.456 12594-12594/com.eggf V/unknown:AbstractDraweeController: controller 43c0de60 1479: set_final_result @ onNewResult: image: CloseableReference 431124b0
10-01 20:58:05.456 12594-12704/com.eggf E/CursorWindow: Could not create CursorWindow from Parcel due to error -12.
10-01 20:58:05.456 12594-12704/com.eggf E/CursorWindow: Could not create CursorWindow from Parcel due to error -12.
10-01 20:58:05.456 12594-12702/com.eggf E/CursorWindow: Could not create CursorWindow from Parcel due to error -12.
10-01 20:58:05.456 12594-12702/com.eggf E/CursorWindow: Could not create CursorWindow from Parcel due to error -12.
10-01 20:58:05.466 12594-12594/com.eggf V/unknown:AbstractDraweeController: controller 43987d70 1481: final_failed @ onFailure: failure: android.database.CursorWindowAllocationException: Cursor window could not be created from binder.
10-01 20:58:05.466 12594-12594/com.eggf V/unknown:AbstractDraweeController: controller 43d8cea8 1482: final_failed @ onFailure: failure: android.database.CursorWindowAllocationException: Cursor window could not be created from binder.
10-01 20:58:05.466 12594-12594/com.eggf V/unknown:AbstractDraweeController: controller 43cbdfc0 1483: final_failed @ onFailure: failure: android.database.CursorWindowAllocationException: Cursor window could not be created from binder.
10-01 20:58:05.476 12594-12670/com.eggf E/CursorWindow: Could not create CursorWindow from Parcel due to error -12.
10-01 20:58:05.486 12594-12670/com.eggf E/unknown:React: Exception in native call from JS
                                                         android.database.CursorWindowAllocationException: Cursor window could not be created from binder.
                                                             at android.database.CursorWindow.<init>(CursorWindow.java:133)
                                                             at android.database.CursorWindow.<init>(CursorWindow.java:41)
                                                             at android.database.CursorWindow$1.createFromParcel(CursorWindow.java:681)
                                                             at android.database.CursorWindow$1.createFromParcel(CursorWindow.java:679)
                                                             at android.database.BulkCursorDescriptor.readFromParcel(BulkCursorDescriptor.java:75)
                                                             at android.database.BulkCursorDescriptor$1.createFromParcel(BulkCursorDescriptor.java:34)
                                                             at android.database.BulkCursorDescriptor$1.createFromParcel(BulkCursorDescriptor.java:30)
                                                             at android.content.ContentProviderProxy.query(ContentProviderNative.java:388)
                                                             at android.content.ContentResolver.query(ContentResolver.java:414)
                                                             at android.content.ContentResolver.query(ContentResolver.java:357)
                                                             at com.facebook.react.modules.camera.CameraRollManager$GetPhotosTask.doInBackgroundGuarded(CameraRollManager.java:296)
                                                             at com.facebook.react.modules.camera.CameraRollManager$GetPhotosTask.doInBackgroundGuarded(CameraRollManager.java:246)
                                                             at com.facebook.react.bridge.GuardedAsyncTask.doInBackground(GuardedAsyncTask.java:34)
                                                             at com.facebook.react.bridge.GuardedAsyncTask.doInBackground(GuardedAsyncTask.java:22)
                                                             at android.os.AsyncTask$2.call(AsyncTask.java:287)
                                                             at java.util.concurrent.FutureTask.run(FutureTask.java:234)
                                                             at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
                                                             at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
                                                             at java.lang.Thread.run(Thread.java:841)
10-01 20:58:05.576 12594-12594/com.eggf E/qdmemalloc: ion: Failed to map memory in the client: Out of memory
10-01 20:58:05.576 12594-12594/com.eggf E/qdgralloc: Could not mmap handle 0x83f64db8, fd=999 (Out of memory)
10-01 20:58:05.576 12594-12594/com.eggf E/qdgralloc: gralloc_register_buffer: gralloc_map failed
10-01 20:58:05.576 12594-12594/com.eggf W/GraphicBufferMapper: registerBuffer(0x83f64db8) failed -12 (Out of memory)
10-01 20:58:05.576 12594-12594/com.eggf E/GraphicBuffer: unflatten: registerBuffer failed: Out of memory (-12)
10-01 20:58:05.576 12594-12594/com.eggf E/qdmemalloc: ion: Failed to map memory in the client: Out of memory
10-01 20:58:05.576 12594-12594/com.eggf E/qdgralloc: Could not mmap handle 0x83f64db8, fd=999 (Out of memory)
10-01 20:58:05.576 12594-12594/com.eggf A/libc: Fatal signal 11 (SIGSEGV) at 0x00000000 (code=1), thread 12594 (com.eggf)

And the memory dump before crashing.

adb shell dumpsys meminfo com.eggf -d
Applications Memory Usage (kB):
Uptime: 2188674 Realtime: 2188666

** MEMINFO in pid 12594 [com.eggf] **



                         Shared  Private     Heap     Heap     Heap
                   Pss    Dirty    Dirty     Size    Alloc     Free
                ------   ------   ------   ------   ------   ------
       Native       16       16       16    57060    29373     1202
       Dalvik    21865    19932    21452    33780    32655     1125
        Stack      396        0      396                           
       Cursor        0        0        0                           
       Ashmem        0        0        0                           
    Other dev   129308    76032    91308                           
     .so mmap     7196     2708     3316                           
    .jar mmap        0        0        0                           
    .apk mmap      362        0        0                           
    .ttf mmap      295        0        0                           
    .dex mmap     3188      488       60                           
   Other mmap       21       12        4                           
      Unknown   109760      984   109744                           
        TOTAL   272407   100172   226296    90840    62028     2327

 Objects
               Views:     3170         ViewRootImpl:        1
         AppContexts:        3           Activities:        1
              Assets:        5        AssetManagers:        5
       Local Binders:       14        Proxy Binders:      109
    Death Recipients:        0
     OpenSSL Sockets:        0

 SQL
         MEMORY_USED:      558
  PAGECACHE_OVERFLOW:      164          MALLOC_SIZE:       62

 DATABASES
      pgsz     dbsz   Lookaside(b)          cache  Dbname
         4      288            208       17/85/16  /data/data/com.eggf/databases/50.db
         4     5544             42         2/78/3  /data/data/com.eggf/databases/RKStorage
         4       40             17         0/72/1  /data/data/com.eggf/databases/webview.db

 Asset Allocations
    zip:/data/app/com.eggf-1.apk:/assets/fonts/Ionicons.ttf: 141K
    zip:/data/app/com.eggf-1.apk:/assets/fonts/FontAwesome.ttf: 149K

It seems the memory usage is not hight. My android phone has 3G RAM.

@oprisnik
Copy link
Contributor

oprisnik commented Oct 3, 2016

Yeah, I think this could be a problem with the scroll / list component then? I think that removeClippedSubviews=true should be correct but I'm not working on React Native. Maybe @astreet can chime in again :)

@reimertz
Copy link

reimertz commented Oct 7, 2016

I just ran into this issue on Android as well. Images just randomly doesn't render and the app has to be restarted to resolve the issues. Looking forward to see this issue resolved. <3

@oprisnik
Copy link
Contributor

oprisnik commented Oct 7, 2016

ScrollView? ListView?

@onepiece-dz
Copy link

i use the 0.34.0 version of react-native and the newest version of Fresco, but this problem is still exist。

@narychen
Copy link
Contributor Author

@MingYe-dz I think the problem that image cannot show will not happen in 0.34.0. This has been fixed by @oprisnik . But the memory still leaks and will finally cause app crash down. Could give some screenshot of what happened in your app?

@Poordeveloper
Copy link

I have this problem too

@narychen
Copy link
Contributor Author

@Poordeveloper Which version ?

@Poordeveloper
Copy link

@narychen "react-native": "0.37.0"

@narychen
Copy link
Contributor Author

@Poordeveloper Could you try the FrescoModule.clearCache() I mentioned above to see if it happens ?

@iamdurui
Copy link

@narychen do you solve this problem?

@narychen
Copy link
Contributor Author

narychen commented Dec 28, 2016

@iamdurui Yeah, I think the problem has been solved.
I didn't use the method @oprisnik provided here. I use my method said above.
I haven't closed the issue because I found that the crash may happen when you browse a lot of images. But when I read the issue of this #499,
I finally feel that the crash may be not caused by the fresco but the listview implementation flaws in react-native.
So the issue could be closed.

@Borisboky
Copy link

I still have the same problem. I'm using React Native 0.39.

I have bunch of images and when user clicks on one of those images it gets zoomed.

The render function is as follows :

return (
    <View style={styles.container}>
        <View style={styles.innerContainer}>
            <View style={{ height: y_vis, width: x_vis}} onStartShouldSetResponder={this.onBullsEyeMove.bind(this)} onMoveShouldSetResponder={this.onBullsEyeMove.bind(this)} onResponderMove={this.onBullsEyeMove.bind(this)} onResponderRelease={this.onBullsEyeSet.bind(this)}>
                 <Image style={{position: 'absolute', top: top * -1, left: left * -1, width: p_width, height: p_height}} source={this.state.item.image} resizeMode="contain"></Image>
            </View>
       </View>
    </View>
)

On iOS it works fine, like is should, but on android not.

Only first time it renders the photo, second time it renders white screen, without photo.
If I click on back or if I go to some other screen in the app and then come back, then it works, but also only the first time when I click, second time I get white screen.

I've tried with adding android:largeHeap to manifest, but no success.

Any idea?

@sy-tian
Copy link

sy-tian commented Sep 13, 2017

Anyone has solution for this?

@lhfiii
Copy link

lhfiii commented Dec 5, 2017

"react-native": "0..51-RC"
still exists

@keermanish
Copy link

It seems issue is still persist. Sometimes images does not load.

Any solution?

@hramos
Copy link
Contributor

hramos commented Jun 25, 2018

@keermanish please open a new issue with any details specific to your problem.

@facebook facebook locked as resolved and limited conversation to collaborators Jun 25, 2018
@hramos hramos added the Resolution: Fixed A PR that fixes this issue has been merged. label Jun 25, 2018
@react-native-bot react-native-bot added the Resolution: Locked This issue was locked by the bot. label Jul 19, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Help Wanted :octocat: Issues ideal for external contributors. Ran Commands One of our bots successfully processed a command. Resolution: Fixed A PR that fixes this issue has been merged. Resolution: Locked This issue was locked by the bot.
Projects
None yet
Development

No branches or pull requests