Hi, I am in the process of building an app that relies on a relatively large amount of network-based images, loaded with the source={{uri: uri}} prop. This works well for a while, but after several minutes of using the app, it seems to have run out of memory for these images. At that point, instead of rendering, new images will either remain blank, or render a black box. The app also starts slowing down and becoming jittery. I have tried to debug with systrace, but I can't for the life of me get the newest version to show traces in any browser,
Since my app is image heavy, I have added the largeHeap directive to my manifest, which helped, but I know that there is a better solution. I also am making sure to request smaller-dimensioned versions of the images. Does anyone have experience freeing memory from network images? This is fairly urgent, and any advice would be most appreciated.
Sam
Same issue here. Even using RN 0.25.1
I tested it on 3 devices.
With getImageCacheSize() from react-native-http-cache I logged the image cache size every second.
After a while the cache stops growing.
On each device it stops at different cache sizes:
| Device | Limit |
| --- | --- |
| One Plus | 40659781 |
| Samsung Galaxy S4 | 24892319 |
| Nexus 5 | 22600605 |
Now I just bruteforce called clearImageCache() every 10 sec.
Didn't solve the problem.
Still after loading many pictures (maybe around 100 - 150), it stops.
So it's probably not related to the image cache, what was my first assumption.
So the problem probably lies in fresco / the bindings to fresco.
New <Image> elements just stay white. No error.
@foghina You implemented some of the RN Android fresco stuff. Have any idea what could cause the problem?
Thanks in advance!
Good thinking, tim. I ran a similar profile on my app, checking the http cache size, the image cache size, and the total, and I noticed that the cache does seem to be regulating itself pretty well. So I think it's a memory problem with something other than the cache.
I am too having this problem recently, I'm using RN 0.25.1.
After using the app for a while, some images renders blank. I simply have to reset content and settings and install the app into my simulator again. All images render fine now.
"react-native": "^0.25.1",
getting this as well rendering 10 images, rendering blank in a ListView, black image otherwise
EDIT: IOS
Update: I've been using Android memory monitor to profile my image-heavy ListView, and no combination of overflow: hidden, removeClippedSubviews, or manual image destruction is yielding a memory reduction. It also doesn't help that onChangeVisibleRows doesn't fire on Android, so building a workaround seems exceedingly difficult. I noticed that images on a route that is then popped from the navigator can indeed be garbage collected, but for routes that are never popped, Images consume a pretty significant chunk of memory.
Any chance that this would fix it?
The solution to that issue was for iOS it looks like - and at this point I am more inclined to believe this is an application-level memory problem, not necessarily one limited to Images. They're just the easiest targets since they consume the largest amount of memory.
Hmm so one "Fix" would be to use WebView for those pictures.
I found this library called react-virtualized so one could use that if you have a ListView with huge amounts of Images.
@timsuchanek how would a webview help? Better memory footprint??
No, but I think that uses the integrated Browser, which should be able to
handle a lot of images without crashing
Am 18.05.2016 2:49 vorm. schrieb "Samuel Purcell" <[email protected]
:
@timsuchanek https://github.com/timsuchanek how would a webview help?
Better memory footprint??—
You are receiving this because you were mentioned.
Reply to this email directly or view it on GitHub
https://github.com/facebook/react-native/issues/7408#issuecomment-219896072
Hmmm, that seems like a pretty good solution memory-wise, but I can't seem to get the images to resize, since I don't have control over that from WebView. Any advice?
It seems that the problem goes away after adding a key to the Image like:
<Image key={some-image-${index}}/>
I have been plagued with this problem as well, especially in debug mode running on Genymotion emulator. I have an app where doing an item selection in a scrollview gets data and shows other images. Sometimes it works, sometimes I get blank images as well. I also do a complex render of up to 200 images in my scrollview and over time will see large numbers of them coming up blank.
As a lot of react-native is based on poking around the internet and using the almost non-existent code examples, I know that I am not rendering correctly. Probably need to do a more (if image has loaded, good, if not get it loaded approach similar to the listview datachanged examples). I've spent a lot of time on this issue, but it is getting too time consuming to find it. Hopefully others will see this post and perhaps show the way they are rendering images.
this is happening to me on RN 0.27.2 as well. i'm going to try workaround provided by @holyxiaoxin
ok the solution didn't work for me, adding a key to images (I render around 200 of them) still gives me blank images, any idea anyone?
I'm also having a similar problem. When I add too many images to my app, they just stop loading. I'm seeing the following in adb logcat:
100s of messages that look like this:
W/unknown:CloseableReference(18531): Finalized without closing: 134069e 195f257f (type = NativePooledByteBuffer)
W/unknown:CloseableReference(18531): Finalized without closing: a29d94c 30cedd95 (type = CloseableStaticBitmap)
And a few crashes like this:
W/InputMethodManagerService( 1130): Session failed to close due to DeadObject
W/InputMethodManagerService( 1130): android.os.DeadObjectException
W/InputMethodManagerService( 1130): at android.os.BinderProxy.transactNative(Native Method)
W/InputMethodManagerService( 1130): at android.os.BinderProxy.transact(Binder.java:496)
W/InputMethodManagerService( 1130): at com.android.internal.view.IInputMethodSession$Stub$Proxy.finishSession(IInputMethodSession.java:305)
W/InputMethodManagerService( 1130): at com.android.server.InputMethodManagerService.finishSessionLocked(InputMethodManagerService.java:1632)
W/InputMethodManagerService( 1130): at com.android.server.InputMethodManagerService.clearClientSessionLocked(InputMethodManagerService.java:1623)
W/InputMethodManagerService( 1130): at com.android.server.InputMethodManagerService.clearCurMethodLocked(InputMethodManagerService.java:1654)
W/InputMethodManagerService( 1130): at com.android.server.InputMethodManagerService.unbindCurrentMethodLocked(InputMethodManagerService.java:1603)
W/InputMethodManagerService( 1130): at com.android.server.InputMethodManagerService.onServiceDisconnected(InputMethodManagerService.java:1680)
W/InputMethodManagerService( 1130): at android.app.LoadedApk$ServiceDispatcher.doDeath(LoadedApk.java:1249)
W/InputMethodManagerService( 1130): at android.app.LoadedApk$ServiceDispatcher$RunConnection.run(LoadedApk.java:1263)
W/InputMethodManagerService( 1130): at android.os.Handler.handleCallback(Handler.java:739)
W/InputMethodManagerService( 1130): at android.os.Handler.dispatchMessage(Handler.java:95)
W/InputMethodManagerService( 1130): at android.os.Looper.loop(Looper.java:135)
W/InputMethodManagerService( 1130): at com.android.server.SystemServer.run(SystemServer.java:290)
W/InputMethodManagerService( 1130): at com.android.server.SystemServer.main(SystemServer.java:190)
W/InputMethodManagerService( 1130): at java.lang.reflect.Method.invoke(Native Method)
W/InputMethodManagerService( 1130): at java.lang.reflect.Method.invoke(Method.java:372)
W/InputMethodManagerService( 1130): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:984)
W/InputMethodManagerService( 1130): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:779)
Is this happening on a device or on genymotion? Is it in debug mode our
did you try a release version? Post the code
On Sep 26, 2016 8:56 PM, "Cxxxx100" [email protected] wrote:
I'm also having a similar problem. When I add too many images to my app,
they just stop loading. I'm seeing the following in adb logcat:100s of messages that look like this:
W/unknown:CloseableReference(18531): Finalized without closing: 134069e
195f257f (type = NativePooledByteBuffer)
W/unknown:CloseableReference(18531): Finalized without closing: a29d94c
30cedd95 (type = CloseableStaticBitmap)And a few crashes like this:
W/InputMethodManagerService( 1130): Session failed to close due to
DeadObject
W/InputMethodManagerService( 1130): android.os.DeadObjectException
W/InputMethodManagerService( 1130): at android.os.BinderProxy.transactNative(Native
Method)
W/InputMethodManagerService( 1130): at android.os.BinderProxy.
transact(Binder.java:496)
W/InputMethodManagerService( 1130): at com.android.internal.view.
IInputMethodSession$Stub$Proxy.finishSession(IInputMethodSession.java:305)
W/InputMethodManagerService( 1130): at com.android.server.
InputMethodManagerService.finishSessionLocked(InputMethodManagerService.
java:1632)
W/InputMethodManagerService( 1130): at com.android.server.
InputMethodManagerService.clearClientSessionLocked(
InputMethodManagerService.java:1623)
W/InputMethodManagerService( 1130): at com.android.server.
InputMethodManagerService.clearCurMethodLocked(InputMethodManagerService.
java:1654)
W/InputMethodManagerService( 1130): at com.android.server.
InputMethodManagerService.unbindCurrentMethodLocked(
InputMethodManagerService.java:1603)
W/InputMethodManagerService( 1130): at com.android.server.
InputMethodManagerService.onServiceDisconnected(InputMethodManagerService.
java:1680)
W/InputMethodManagerService( 1130): at android.app.LoadedApk$
ServiceDispatcher.doDeath(LoadedApk.java:1249)
W/InputMethodManagerService( 1130): at android.app.LoadedApk$
ServiceDispatcher$RunConnection.run(LoadedApk.java:1263)
W/InputMethodManagerService( 1130): at android.os.Handler.
handleCallback(Handler.java:739)
W/InputMethodManagerService( 1130): at android.os.Handler.
dispatchMessage(Handler.java:95)
W/InputMethodManagerService( 1130): at android.os.Looper.loop(Looper.
java:135)
W/InputMethodManagerService( 1130): at com.android.server.
SystemServer.run(SystemServer.java:290)
W/InputMethodManagerService( 1130): at com.android.server.
SystemServer.main(SystemServer.java:190)
W/InputMethodManagerService( 1130): at java.lang.reflect.Method.invoke(Native
Method)
W/InputMethodManagerService( 1130): at java.lang.reflect.Method.
invoke(Method.java:372)
W/InputMethodManagerService( 1130): at com.android.internal.os.ZygoteInit$
MethodAndArgsCaller.run(ZygoteInit.java:984)
W/InputMethodManagerService( 1130): at com.android.internal.os.
ZygoteInit.main(ZygoteInit.java:779)—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
https://github.com/facebook/react-native/issues/7408#issuecomment-249739072,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAUnhsdXAa13IAAC0aH0uJeEJcP60seZks5quGnFgaJpZM4IYIrA
.
This is on a device running a debug version.
I can't seem to reproduce the DeadObjectException today, perhaps it was unrelated. But here is some sample code that causes the CloseableReference warnings and the images stop loading:
import React from "react";
import {
AppRegistry,
Image,
ScrollView,
StyleSheet,
Text,
TouchableHighlight,
View
} from "react-native";
AppRegistry.registerComponent("AwesomeProject", () =>
React.createClass({
render() {
var imageMap = [
"https://avatars2.githubusercontent.com/u/22461323",
// ...
// More Images as necessary, I needed ~ 200 to trigger the issue
"https://avatars2.githubusercontent.com/u/22461323"
];
return (
<View>
<Text>Lots of Images</Text>
<ScrollView
horizontal={true}
automaticallyAdjustContentInsets={false}
directionalLockEnabled={true}>
{imageMap.map((imageUri, i) =>
<TouchableHighlight key={i}>
<Image style={styles.image} source={{ uri: imageUri }} />
</TouchableHighlight>
)}
</ScrollView>
</View>
);
}
})
);
const styles = StyleSheet.create({
image: {
width: 150,
height: 150,
marginHorizontal: 20,
resizeMode: "contain"
}
});
Try something. First of all wrap the touchable highlights with a
Brian B. Canin brian.[email protected]
858-945-5601 (cell)
On Wed, Sep 28, 2016 at 3:11 PM, Cxxxx100 [email protected] wrote:
This is on a device running a debug version.
I can't seem to reproduce the DeadObjectException today, perhaps it was
unrelated. But here is some sample code that causes the CloseableReference
warnings and the images stop loading:import React from "react";
import {
AppRegistry,
Image,
ScrollView,
StyleSheet,
Text,
TouchableHighlight,
View
} from "react-native";AppRegistry.registerComponent("AwesomeProject", () =>
React.createClass({
render() {
var imageMap = [
"https://avatars2.githubusercontent.com/u/22461323",
// ...
// More Images as necessary, I needed ~ 200 to trigger the issue
"https://avatars2.githubusercontent.com/u/22461323"
];return ( <View> <Text>Lots of Images</Text> <ScrollView horizontal={true} automaticallyAdjustContentInsets={false} directionalLockEnabled={true}> {imageMap.map((imageUri, i) => <TouchableHighlight key={i}> <Image style={styles.image} source={{ uri: imageUri }} /> </TouchableHighlight> )} </ScrollView> </View> ); } }));
const styles = StyleSheet.create({
image: {
width: 150,
height: 150,
marginHorizontal: 20,
resizeMode: "contain"
}
});—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
https://github.com/facebook/react-native/issues/7408#issuecomment-250268618,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAUnhhe_Og8DA0ZMoSxecd86nTKs83B1ks5qurvmgaJpZM4IYIrA
.
I made the suggested changes, but I'm still seeing the warnings and the images stop loading.
Ok I think I understand what you are trying to do and I think I understand the problem....
You are requesting a network image. You can't just do that as the time it takes to pull down the network image (especially when there are a lot of them) is going to lock up the thread. The way to get around this is to use the onLoad function which will trigger when the image has actually come down.... I wrote this to help you, but the best way is to look at:
http://moduscreate.com/how-to-use-image-placeholders-in-react-native/
Basically you need to update your state so when an image DOES get fully downloaded, you can rerender it. Right now, the images are still downloading, but the render immediately shows the images (they aren't there yet so you get a blank).
Here is what I wrote from what you had....
componentWillMount() {
this.getDirectories(this.state.the_path);
let lrp = [];
for (let x1 = 0; x1 < imageMap.length; ++x1) {
lrp.push(true);
}
this.setState({loading: lrp});
}
render() {
return (
<View>
<Text>Lots of Images</Text>
<View style={{flexDirection: 'row'}}>
<ScrollView
horizontal={true}
height={800}
automaticallyAdjustContentInsets={false}
directionalLockEnabled={true}>
{imageMap.map((imageUri, i) => this.get_images(imageUri, i))}
</ScrollView>
</View>
</View>
);
}
get_images(imageUri, i) {
var the_Uri = {uri: imageUri};
var loader = this.state.loading[i] ?
<View key={i}>
<Text>Loading...</Text>
</View> : null;
return(
<Image
key={i}
source={the_Uri}
style={[styles.image, {overflow: 'visible'}]}
onLoad={()=> {
let lrp = [];
lrp = this.state.loading.slice(0);
lrp[i] = false;
this.setState({loading: lrp})}}>
{loader}
</Image>
)
}
So when any item does finally load, it updates the state.loading array (you can't directly set an element in a state array, you need to copy it to a temp and then set the whole thing...
This works, but again look at the URL above, they have a nice elegant way of getting network images...
Hope this helps.
I'm running into this issue on RN v0.33.1 on a physical Samsung Galaxy S7
@cyphire I tried your solution but the onLoad function is never fired for any image after a certain number load so it doesn't work.
Implement the link I sent, that's the right way to do it... You keep
getting network assets and by updating state will do placeholders then show
image. Will work for any number because it's an async call...
On Sep 30, 2016 10:55 AM, "ghuh" [email protected] wrote:
@cyphire https://github.com/cyphire I tried your solution but the
onLoad function is never fired for any image after a certain number load so
it doesn't work.—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/facebook/react-native/issues/7408#issuecomment-250765427,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAUnhrh_E9sWiCQZEmBG0Mo1zgbYO-6Fks5qvSLMgaJpZM4IYIrA
.
The link still doesn't solve the problem, it's just showing how to display placeholders while data loads. That's certainly a good thing to do but some images still are simply not loading.
Are you in debug mode? Sometimes large number of images don't load because
the normal development mode is slow because of being able to debug...
If you've set up release mode "gradlew assembleRelease" in android
directory (or the equiv in iPhone) try it in release mode....
Also - I know it's not your problem but in Genemotion sometimes after a
while all the images stop showing (all images)...
Brian B. Canin brian.[email protected]
858-945-5601 (cell)
On Fri, Sep 30, 2016 at 4:31 PM, ghuh [email protected] wrote:
The link still doesn't solve the problem, it's just showing how to display
placeholders while data loads. That's certainly a good thing to do but some
images still are simply not loading.—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/facebook/react-native/issues/7408#issuecomment-250844688,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAUnhjiRD2lXXyXxyrLtY6Fd1sQKg_ryks5qvXGIgaJpZM4IYIrA
.
I'm testing on a physical Samsung Galaxy S7 with a release mode build
If you're new to React-Native send the appropriate part of the code if you
want... maybe i'll see something...
Brian B. Canin brian.[email protected]
858-945-5601 (cell)
On Fri, Sep 30, 2016 at 5:53 PM, ghuh [email protected] wrote:
I'm testing on a physical Samsung Galaxy S7 with a release mode build
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/facebook/react-native/issues/7408#issuecomment-250861016,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAUnhhE8GridtZshvZiWtZcNsjv8vENuks5qvYTVgaJpZM4IYIrA
.
Does anyone know if this is a problem when doing native Android development or is this specifically a RN problem?
Also, I've tested my exact same code on iOS (iPhone and iPad, simulator and real) and not had any issues so this is definitely an Android issue.
We are also trying to deal with this issue.
It seems the problem is with React's custom JPG decoder. They have a home-built bucket based memory allocator where they are shoving all these raw images. At some point it runs out of memory and starts throwing errors, which are then swallowed because Android version of Image doesn't have onError event hooked up.
From BasePool.java:
// check to see if we can allocate a value of the given size without exceeding the hard cap
sizeInBytes = getSizeInBytes(bucketedSize);
if (!canAllocate(sizeInBytes)) {
throw new PoolSizeViolationException(
mPoolParams.maxSizeHardCap,
mUsed.mNumBytes,
mFree.mNumBytes,
sizeInBytes);
}
On the upside, it seems this is only done for certain image formats. So the solution we are exploring right now is not serving JPEG-s to android at all.
From ImageDecoder.java:
public CloseableImage decodeImage(
final EncodedImage encodedImage,
final int length,
final QualityInfo qualityInfo,
final ImageDecodeOptions options) {
ImageFormat imageFormat = encodedImage.getImageFormat();
if (imageFormat == null || imageFormat == ImageFormat.UNKNOWN) {
imageFormat = ImageFormatChecker.getImageFormat_WrapIOException(
encodedImage.getInputStream());
}
switch (imageFormat) {
case UNKNOWN:
throw new IllegalArgumentException("unknown image format");
case JPEG:
return decodeJpeg(encodedImage, length, qualityInfo);
case GIF:
return decodeGif(encodedImage, options);
case WEBP_ANIMATED:
return decodeAnimatedWebp(encodedImage, options);
default:
return decodeStaticImage(encodedImage);
}
}
From our tests, it seems the problem disappears with PNG-s. Looking into other image formats right now, as PNG is ill suited for full colour images.
Disregard the PNG solution. It doesn't work after all. It goes through the same decoder code.
It sounds like there are a number of different things going on in this thread, and it's somewhat of a guess, but all of it sounds like a symptom of the app running out of memory. There isn't going to be one solution to that, though, so it's hard to make progress on this overall issue. I think if people can reproduce this on a small app where there isn't some other part of the app making it run out of memory, it would be pretty good evidence that there really is a problem specifically with images. Otherwise, I think the most reasonable thing to assume with these symptoms is that your app is leaking memory or just using too much, and the thing to do is profile your memory usage. I am going to close this thread, but I think people should feel free to reopen a new issue if 1/ this problem is happening in a situation where the app is clearly not running out of memory overall or 2/ this is happening in an app where there's just one behavior that's Image-specific.
Hey Kevin, I'm going to request that you keep this issue open. If you look at the code I posted on September 28th, that's literally my whole react app and the issue still reproduced. This would be your option 2/ from above "this is happening in an app where there's just one behavior that's Image-specific".
Also as a side note, if I load the same number of images in a webview, I don't run into the issue. So I think the issue is specific to the React Image component logic leaking memory and not just "Your app has too many images"
@Cxxxx100 OK, that does seem like a valid problem, but your comment is also the 17th one on this issue, so I think people coming to this issue will not actually be looking at your sample code in order to reproduce it. Would you mind opening a new issue, and providing the sample code of your app that reproduces this problem up front? I think that will be more effective in getting attention on it.
@lacker Sure, I've opened https://github.com/facebook/react-native/issues/10569
This issue is about Android memory management.
I solved this by adding android:largeHeap="true" to AndroidManifest.xml Application section.
Try to avoid using largeHeap option. It may cost you hard-to-notice performance drop and bad user experience.
@janaka120, so what alternatives do I have if I want to have a lot of images in my application?
Without largeHeap="true" images loads randomly and most of them are blank.
@adamfaryna, I create a sample app with 500 images. it works fine without give any errors. I try to keep every image size less than 200kb. I think this might help you.
@janaka120 thanks, but it doesn't work for me. My application has only 50 images displayed on single screen with ListView (you can find it here https://goo.gl/se4pgH - Android version only right now). All images are less than 120kb. Only part of them are displayed on Android.
I'm using [email protected]. Which version of RN are you using?
I used RN 0.38.0 version
Same issue, don't know how to fix :(.
At the beginning, app works fine, after some minutes, images are blanked out and some time the app is crashed and stop working.
React native version 0.41.2
The same in 0.42.0
The reason is mentioned in react-native page officially ([http://facebook.github.io/react-native/releases/0.20/docs/known-issues.html]), the only thing we can do now is that try to load images with the size as small as possible, exp: load thumbnail for small images. My solution is whenever uploading any image to server, server will save that image to 3 versions: thumbnail, medium and large. Then we load images with specified size base on the demand. I resolved this issue by using this way.
@sampurcell93 hey in my app in android images automatically gets stored in gallery how can i avoid that
Most helpful comment
It seems that the problem goes away after adding a key to the Image like:
<Image key={some-image-${index}}/>