I've come across a strange problem - I'm making an android game and noticed a lag every few seconds and checked the logs when I noticed the garbage collector was being called every few seconds for 50-150ms a go.
I've whittled this problem down to the images, when I launch my title screen activity, using one background image (150kb) - the messages i get are:
4% free (8009k/8259k)
GROW HEAP to 9.012MB
GC_CONCURRENT freed 1kb (9178k/9479k)
Which is a lot of heap space for an image and three buttons. When I remove the image, I get no warnings or messages (not sure how to force an output on heap-space, but I hope it's at normal levels)
The code for the activity image isn't that exciting as it's just a title screen, but:
<ImageView
android:id="#+id/backgroundImage1"
android:contentDescription="Image"
android:src="#drawable/openingscreen"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="top"
/>
When I launch the actual game the heap size increases again (only by a few mb's) -- the weird thing is when I didn't have the title screen, the heap space for the main game was still 12 or so mb's - so I'm thinking maybe the image is holding a reference to everything else. Although I tried using a background image of 1 pixel in size and this caused no problems.
Secondly, the code for images inside the gameThread:
mPlayer = Bitmap.createScaledBitmap(mPlayer, mCanvasWidth / 15, mCanvasHeight / 8, true);
canvas.drawBitmap(mPlayer, xPosition, yPosition, null);
I did hear somewhere that scaling bitmaps can cause memory problems, but that doesn't really add up with everything else.
Yes,a lot of developers while developing has faced this situation.
What i would ask you to do is a thorough study check of what exactly this heap is,how the garbage collector handles it,how can you efficiently use or even scale bitmaps
You could first start with going through this video
Google Android Memory Management
Next in the android developers site, go through in detail
Displaying bitmaps efficiently
Last and final thing start a habit of using MAT(Memory analyzer Tool),there are tutorials,lessons a lot of blogs on how to use it and finding out where and why the app is being deprived of memory
Following formular tells you how much heap space an image take: width x height x 8 bytes. So an image thats all white but large in size will still take a lot of heap space.
Just updating, I found out the main problem in my code and managed to get it running smoothly, I doubt anybody else is stupid enough to make the same mistake but I'll post my solution just in case!
I was re-sizing my images every iteration of the game, I somehow didn't realize I put the code in there, changed it so it re-sizes them at the very start and that's it. But there it is, I doubt this solution will help anybody, but perhaps one day it will!
Kevin.
Related
I am getting random out of memory exceptions in my app caused by inflate exceptions.
I have 7 fragment (difficulty) activities which launch their own activities via buttons. Each fragment has a scroll view with 30 buttons (levels).
I have set it up so that i can swipe across to each fragment and the fragment takes up the entire screen.
Occasionally when i swipe a few times and then select a random button from a group of 30 it will crash. It tries to load the activity and gives an out of memory exception with an inflate exception on a random line. The line always falls on an imageView or imageButton in the xml file. The activities that load are a grid of imageViews and imageButtons.
I do not get the exception much but it is something i want to fix. I have looked at many other out of memory exception questions although none have helped me. I have done a Memory analyser test and it shows nothing out of the ordinary.
I believe that the imageViews and imageButtons are using too much memory, although i only ever have one activity open at once.
It IS because of your images that are loading. When you load an image and you move around the page and view another image the heap increases. As you continue the process of viewing random images the heap grows even more until your app crashes. It's like stacking books on a glass table. You either move(cache) a book(image) or the glass(app) breaks. You should use an imageloader to load your images.
https://github.com/nostra13/Android-Universal-Image-Loader
You've mentioned that it always falls on an ImageView and ImageButton - and this is the clue to solve this problem. You get OOM 'cause background resource of this view has high resolution and takes a lot of memory. Try to lower resolution of this image.
Also you've mentioned that you have a ScrollView and this means that you keep in memory every 30 items. Probably you'd better change it to RecyclerView backed by adapter.
Just had the same problem and I'd like to simplify all the things said here:
Simply: reduce your images sizes.
Don't use 1080X1920 images... It's too high res.
Such image, even if compressed, when deployed will catch about 1080X1920X4B = 8.2MB (The GPU has to deploy it to it's full original resolution... That's why compression won't help but reducing the needed memory size...) and this i RAM that we're talking about..
Take Gimp or Photoshop and down scale the image to, say, 1/4: 540X960, and you won't feel the difference.. Belive me, been there already.
Beware of the memory consumption of images and videos.
Hope this helps,
James
I am part of a team developing a commercial media app. Part of the functionality is to allow the user to customise a ViewGroup montage of ImageViews with their own images retrieved either from Gallery or direct from Camera. I am using the following Picasso call to do this:
mPicasso.load(uri)
.resize(newWidth, newHeight)
.into(container);
where mPicasso is Picasso.with(appContext()) and newWidth and newHeight are dimensions calculated from the source height and width such that aspect ratio is maintained and the resulting image is 1MP. Typically, the sources are between 8 and 16MP.
If I have a montage of say, eight ImageViews, and I keep adding images to each one in turn, the app eventually crashes. Device only has so much memory, right? Eventually if you keep adding infinite images you're going to run out. What really concerns me, however, is that the app will crash half-way through replacing the eight images. To be clear, you've added your eight images and you've gone back to the top and started replacing those images with different ones and you get to roughly the fourth before the crash.
I would have expected that once an image has been replaced, the old one would be cleaned up. I can fix this by reducing the max size down to 100KP but the problem with that is I imagine I am just delaying the crash. Furthermore, the user has the ability to zoom the image and with such a low resolution, it starts to look knarly quite quickly.
I have posted the crash log here:-
https://gist.github.com/mylesbennett/452c992f6912039ea62d
because it's too long to paste direcly in stackoverflow.
Any suggestions of workarounds/ fixes etc. would be greatly appreciated.
(the crash point in TemplateImageView.isScaleInitialised is where the app is attempting to allocate memory to a nine-value float array:
float[] values = new float[9];
so I am guessing that this is just the straw that broke the camel's back)
My app is getting crashed (throws OutOfMemoryError) when I try to load images in a ViewPager. Here are the details.
All the images are 720*1280 in dimension with 100-150KB in size.
I even tried using Fragments in a Viewpager to load images.. but after sliding one or two images the app gets crashed.
Any pointers on how to resolve this?
Thanks!!
720*1280*32 = 29491200 bits = 3.52 mb each one in memory.
Checkout this tutorial :)
Out of memory error means exactly what is stays. The application is trying to allocate to much memory. Android application are (depending on device) allowed to allocate 30-50MB.
The problem with the view pager is that it tries to hold at least 3 pages (current previous and next) to provide fluent UI work.
Bitmap to be displayed needs to uncompressed. So the only thing that matters is the size (pixel number) and color depth.
Usually 3 bitmaps of size you given should be quite easy hold on the device. I suppose that you are trying to process them in some not proper way, or you are missing releasing them from memory. Can't say more not knowing what are you doing with those bitmaps.
I'm currently trying to create a game for a tablet device for Android using a SurfaceView. I have sprites and what not, but I'm struggling if I should use a whole spritesheet (With every animation in it), or just seperate the sprites on image files.
For example, my spritesheet is named bear.png, which contains 16 images inside. I can animate them beautifully using Rect (Thanks to mybringback for this):
canvas.drawBitmap(bitmap, rectSrc, rectDest, null);
But, I fear doing so would grow to larger than the heap size eventually.
However, there is another method. By seperating each image (bear1.png, bear2.png until bear16.png), I will also be able to create an animation with these sprites via:
Bitmap bitmap = Bitmap.decodeResource(context.getResources(), context.getResources().getIdentifier("bear" + index, "drawable", "com.example.game"));
then calling that to the canvas:
canvas.drawBitmap(bitmap, bitmapX, bitmapY, null);
Which also works fine for now. And of course, it greatly reduces my heap size since I'm only using 1 image at a time. But, because well.. Because, I'd be recalling Bitmap.decodeResource() at almost all times, I fear that when putting many animations together at one time, it may cause a significant lag.
So in short:
- Spritesheets: Increased heap size (which may eventually lead to an OutOfMemory error), but better performance
- Sprites on different image files: Decreased heap size, but may hinder performance
I'm not entirely sure which approach to use. Would it actually be okay if I go with the second method (Sprites on different image files)? Or would it be better with just spritesheets?
Never mind, I just answered my own question. It appears that rendering Bitmap.decodeResource() on every iteration lags the whole canvas, rather than rendering actual spritesheets and using Rect. Performance-wise, if experiencing too much lag on the canvas, there's no other way other than to shrink images using inSampleSize or using GLSurfaceView.
I wanted to ask this question that was asked a few times before. Sorry if I am re-itterating but it is not clear to me as to what is the best solution here.
The question is "how to clean ImageView bitmap resource after its been used so we don't have references to it in memory?".
Here is an example:
Screen 1 redirects to Screen 2
Screen 2 contains control A (preview of large photo)
Control A contains ImageView B
ImageView B is set when control A is initiated
Everything works fine the first time around. Once control A is done I redirect from Screen 2 to Screen 1. At this point all references of control A or ImageView B or Bitmap that its using should be dead. THEY ARE NOT!!!
I've tried all kinds of solutions including bitmap.recycle(), adding finalize() into Control A, System.gs() and nulling control in variouse places such as onStop() and onDestroy(), and everything else that's on screen 2, nothing works!
The problem is when I revisit the screen second time around so going from screen 1 to screen 2 (i.e. creating preview of photo again) I get out of memory exception. It is my understanding that the reference of the previous bitmap is not cleaned up.
How do I KILL it just before I redirect back to Screen 1?
One thing I noticed. If I reduce the size of the photo by, say cropping or making a smaller size of the image everything goes smooth, few times... before I get same issue. So basically it just takes a bit longer to fill up.
I would really appreciate some solution here as this is critical.
You probably have a memory leak , this video might help you in finding the problem Google I/O 2011: Memory management for Android Apps.
Note : pre 3.1 bitmaps are store in VM heap memory but in native memory , which causes lot of problems in noticing leaks,for further info refer the video
Have a look at how WeakReference is used.