What is the issue which will cause the app crash when a user opens the app?
I integrate with HockeyApp, the error shown:
VMRuntime.newNonMovableArray java.lang.OutOfMemoryError: Failed to allocate a 63701004 byte allocation with 16777056 free bytes and 41MB
until OOM
Xamarin caused by: java.lang.OutOfMemoryError: Failed to allocate a 63701004 byte
allocation with 16777056 free bytes and 41MB until OOM
dalvik.system.VMRuntime.newNonMovableArray(Native Method)
android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
android.graphics.BitmapFactory.decodeStreamInternal()BitmapFactory.java:639
android.graphics.BitmapFactory.decodeStream()BitmapFactory.java:615
android.graphics.BitmapFactory.decodeStream()BitmapFactory.java:653
Answer
I already solve the problems with
Update the Xamarin.Forms Nuget.
Delete the package file in the solution.
Build the Solution again.
Add in your manifest these lines android:hardwareAccelerated="false" , android:largeHeap="true" it may solve your issue(s).
<application
android:allowBackup="true"
android:hardwareAccelerated="false"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:largeHeap="true"
android:supportsRtl="true"
android:theme="#style/AppTheme">
I had the same issue. It turned out that multiple changes solved the problem.
Firstly, I ensured that my app can deal with large memory heaps. This is a setting you can set/change in the app's manifest:
<application
...
android:largeHeap="true"> <!-- This line does the trick. -->
Secondly, I made sure that I enforce small image sizes wherever possible. In my case I decided to limit the max resolution to either 720 pixels or the screen resolution, whatever is smaller. As a result I resized large images:
int maxImageSideLength = Math.Min(720, Math.Max(myScreenHeight, myScreenWidth));
// see tutorials how to resize the image now
Lastly, I ensured to dispose image bitmaps (used memory) that where assigned to image views before I assigned a new image. I am uncertain whether this is really necessary as I can't believe that assigning a new image bitmap isn't cleaned up properly, but I left this in my code and I am still happy with a smoothly running app. Example:
Bitmap resizedImage = ResizeImage(fileName, maxImageSideLength);
imageView.SetImageBitmap(null); // this is to free allocated memory
imageView.SetImageBitmap(resizedImage);
GC.Collect(); // dispose of the Java side bitmap
Related
I am displaying images from the internet in a vertical ListView. I fetch the images using http.get (not using cached network image cuz I do not want to cache the images). Then I insert the image Uint8List into image.memory(). What happens is that as the user scrolls the list and images are loading, the ram keeps increasing until the whole app crashes. Any ideas what to do ?
Yeah, this is the normal behavior. I don't know why exactly. My theory is that the images by default are disposed if the dart objects holding references to them are garbage collected rather then when the widgets are knocked off the widgets tree, but don't take my word for it- that's just my personal reasoning. It may be completely wrong.
To get around this, I use Extended Image pakcage It's constructors take a bool clearMemoryCacheWhenDispose which disposes of images in RAM in scroll lists. You may do that or visit the package code to see how he's doing it, and replicate it.
Other advice I can give is to make sure your images are of the appropriate size. If you are loading your images locally check this part of the documentation to have different dimensions selected for different screen sizes https://flutter.dev/docs/development/ui/assets-and-images#loading-images
If you are fetching your images from network which is more likely, make sure their sizes are appropriate, and have different sizes served if you can. If you don't have control over that set cacheWidth and cacheHeight in Image.memory these will reduce the cached image in memory (RAM). You see by default Flutter caches images in full resolution despite their apparent size in the device/app. For example if you want your image to display in 200x200 box then set cacheWidth to 200 * window.devicePixelRatio.ceil() you will find window in dart:ui, and if you only set cacheWidth, the ratio of your images will remain true. Same true if you only set cacheHeight. Also do use ListView.builder as suggested.
I am disappointed at how little is said about this in Flutter docs. Most of the time people discover this problem when their apps start crashing. Do check your dev tools regularly for memory consumption. It's the best indicator out there.
Cheers and good luck
I was having the same issue and found a fix thanks to #moneer!
Context:
Users in my app can create shared image galleries which can easily contain several hundred images. Those are all displayed in a SliverGrid widget. When users scrolled down the list, too many images were loaded into RAM and the app would crash.
Things I had already implemented:
Image resizing on the server side and getting the appropriate sized images on the client based on the device pixel ratio and the tile size in the gallery
I made sure that my image widgets were properly disposing when out of view, but the memory size kept building up as the user scrolled through all the images anyway
Implement cacheHeight to limit the size of the cached image to the exact size of the displayed image
All these things helped but the app would eventually still crash every time the user scrolled down far enough.
The fix:
After some googling I stumbled upon this thread and tried the extended_image_package as #moneer suggested. Setting the clearMemoryCacheWhenDispose flag to true fixed the issue of the app crashing as it was now properly clearing the images from memory when they were out of view. Hooray! However, in my app users can tap on an image and the app navigates to an image detail page with a nice Hero animation. When navigating back the image would rebuild and this would cause a rebuild 'flicker'. Not that nice to look at and kind of distracting.
I then noticed that there's also an enableMemoryCache flag. I tried setting this to false and that seems to work nicely for me. The Network tab in Dart DevTools seems to show that all images are only fetched from the network once when scrolling up and down the gallery multiple times. The app does not crash anymore.
I'll have to more testing to see if this leads to any performance issues (if you can think of any please let me know).
The final code:
ExtendedImage.network(
_imageUrl,
cacheHeight: _tileDimension,
fit: BoxFit.cover,
cache: true, // store in cache
enableMemoryCache: false, // do not store in memory
enableLoadState: false, // hide spinner
)
I had a similar issue when I loaded images from files in a ListView.
[left-side: old code, right-side: new code]
The first huge improvement for me: not to load the whole list at once
ListView(children:[...]) ---> ListView.builder(...).
The second improvement was that images are no longer loaded at full-size:
Image.file("/path") ---> Image.file("/path", cacheWidth: X, cacheHeight: Y)
These two things solved my memory problems completely
Ideally caching happens kind of by default after some conditions are fulfilled. So its upon your app to be responsible to handle and control how the caching will happen.
Checkout this answer
https://stackoverflow.com/a/24476099/12264865
I am having some memory issues with our android app when handling bitmaps (duh!).
We are having multiple activities loading images from a server, this could be a background image for the activity.
This background image could be the same for multiple activities, and right now each activity is loading its own background image.
This means if the flow is ac1->ac2->ac3->ac4 the same image will be loaded 4 times and using 4x memory.
How do I optimize imagehandling for this scenario? Do I create an image cache where the image is stored and then each activity ask the cache first for images. If this is the case, how do I know when to garbage collect the image from the cache?
Any suggestions, link to good tutorials or similar is highly appreciated.
Regards
EDIT:
When downloading images for the device the exact sizes is used, meaning that if the ui element needs an 100x100 pixel image it gets that size and therefore no need for scaling. So i am not sure about downscaling the image when loading it into the memory. Maybe it is needed to unload images in the activity when moving on the the next and then reload when going back.
One thing you might want to try is scaling down your bitmaps (make a thumbnail) to a size that is more appropriate to your device. It's pretty easy to quickly use up all the RAM on an Android device with a bitmap if you don't scale it down. This recipe shows how to do so on the fly. You could adapt this to save the images to disk.
You could also create your own implementation of the LRUCache to cache the images for your app.
After ready your update I will give you an other tip then.
I can still post the patch too if people want that..
What you need to do with those bitmaps is call them with a using block. That way Android will unload the bitmap as soon as that block is executed.
Example:
using(Bitmap usedBitmap = new Bitmap()){
//Do stuff with the Bitmap here
//You can call usedBitmap.Dispose() but it's not really needed
}
With this code your app shouldn't keep all the used bitmaps in memory.
I just try to put Animated gif file with 6 frames acquired from url Request and create nsimage with the response ,,, then set the Image in NSImageView ...
I use this
// Where returnedImage is nsImage I created with response of the connection ..
[myImageView setImage:[response returnedImage]];
I use this code to change the Image displayed when some user actions happen
I observe that The memory allocated to the program is increased linearly with large scale .. and the application might crash
I make sure that my code has no leaks ...
I do not Know why it is increases , do I have to release the previous Image that was set
Any Idea will be appreciated.
I delete and recreate the NSImageView In the Nib File ... I may be an xcode Deployment bug or something ,,, But i was allocate some memory to graphics card continuously increasing
I plan to use a background image for each of my pages in WP7 and not keep the background transparent.
Any suggestions or issues I need to be aware of?
Also, I noticed a CacheMode property.
Can I use that to improve performance if each of the pages will have the same background stretching across the entire page?
2 steps:
(1)
in <phone:PhoneApplicationPage
set shell:SystemTray.IsVisible = "False"
(2)
<Grid x:Name="LayoutRoot">
<Grid.Background>
<ImageBrush ImageSource="Assets/Images/Flowers.png"></ImageBrush>
</Grid.Background>
You can create an Image control sized to full the display and lay your other controls in front of it.
If there is a reason you expect this control to be redrawn, then bitmap caching will save you the overhead of rasterising the control repeatedly.
You can put it on the PhoneApplicationFrame instead of puttin it on each page: it will then load only once and for all...
There are a couple of performance issues you should be aware of:
1) Ensure large images are compiled as Content and not Resources. Compiling as Resource will build the image into the binary executable itself, which makes it much larger to load in to memory on startup.
Jeff Wilcox:
If you’re using Panorama, a Resource
background will load immediately
compared to Content
2) Unless you really need transparency use .jpg files rather than .png. The .jpg decoding algorithm is significantly faster than .png. However beware of compression. What is a tiny image on disk consume much more memory once it has been decompressed in memory.
I'm developing an app for WP7 (VS2010 Express for Windows Phone RTM and WP Emulator), but now im facing a big problem related to memory usage.
The app itself has like 12 views, and some of them are reused with different data. It's a newsreader, so the views are mostly listboxes (image thumbnail, stackpanels and textblocks).
The first view has a listbox with 30 items. This takes about 20MB of RAM, but as i navigate between views the current and peak RAM usage start to rise. Well the peak usage it's around 55MB which i think is OK, but the app has a gallery section in which after selecting a thumbnail it navigates to another view which displays a downloaded image (JPEG, 1131px × 1647px, ~486KB) but initially fit to the screen. Until here all good, but for scaling purposes i'm using Laurent Bugnion's Multitouch Behavior and the problem is that when i zoom in the image, the memory usage gets near 90MB (like 87MB last time i tested with the maximum scale size at 2.5).
Also after i navigate the views the current ram usage may permantly reach and stay at 35MB, which i beleive is due to the device caching some things.
So, as the title says, how can i avoid such huge ram usage?
Edit----
Also i'd like to ask if the fact that in my app one can navigate from any view to almost every other and that in between there's always a page transition animation (like the one for the phone list application template in the beta tools), may be contributing to the excessive memory usage.
Generally speaking you want to keep images as small as feasible (in dimensions and color depth, not necessarily file size). In order to display an image, the device must decompress it to an actual Bitmap, so in this case you're looking at a 1131x1647pixel image, let's say at 16bpp, means that you have a 3.7MB memory footprint for the image, not the 486k file size.
Depending on your zoom/rotate, there may be a second copy buffer, so you can effectively double that. It doesn't take long at that rate to get to 90MB. I'd certainly try either download smaller image files or try resizing them locally and then using the resized image.
Well maybe i should look into deepzoom (but when i first read about it, i thought it was for using it with the same image at different sizes, like google maps in satellite view), but yesterday i solved it by using a webbrowser inside my view, so if before i had:
<Image x:Name="imgPlaceHolder" delay:LowProfileImageLoader.UriSource="{Binding Path=ActualImageSource}" MaxHeight="800"
MaxWidth="480" >
<interac:Interaction.Behaviors >
<tbeh:MultiTouchBehavior x:Name="ImageMTB" IsScaleEnabled="True"
MinimumScale="0.4"
MaximumScale="2.5"
IsRotateEnabled="False"
IsDebugModeActive="False"
IsTranslateXEnabled="True"
IsTranslateYEnabled="True"
>
</tbeh:MultiTouchBehavior>
</interac:Interaction.Behaviors>
</Image>
I changed that to:
<phone:WebBrowser Source="{Binding Path=ActualImageSource}" x:Name="wbbigimage" />
It uses less memory and takes care of the zoom with no problems.
I'll wait a bit for someone with a better solution before checking this one.
A couple of things to note. First, make sure that you are clearing out any lists or images that you are using on pages durring the onNavigatedFrom method. The way WP7 Deals with images is "interesting". One of the things I have found to help is to null out the background of any panorama controls when the page is not being displayed.
As for your specific issue, have you considered using a MultiScaleImage (Deep Zoom) to cut down on memory?
http://msdn.microsoft.com/en-us/library/system.windows.controls.multiscaleimage(VS.95).aspx