We have an app where we draw many things (mostly OpenStreetMap Tiles but also other images) with OpenGL ES 2.0. This works pretty good, but from time to time the app crashes without any information - this means: The app just closes, not a message that it is crashed and also there is no message in logcat.
From experiments we've figured out, that the app crashes after loading too many textures into OpenGL (glGenTextures/glBindTexture
)
In an experiment on a Samsung galaxy S3 we are able to load up to 1800 textures with a size of 256x256 in RGB888 standard. After that our app crashes without any error logs. Shouldn't we receive an error(GL_OUT_OF_MEMORY
) when we are constantly checking for OpenGL Errors (GLES20.glGetError
) while loading textures?
Generally asked: Is there a way to determine the maximum size available in gpu memory or at least, how do we get a warning as soon as we are running out of memory? (The problem is we do not know WHEN we should start deleting handles and we want to keep most of them as long as possible...)
Thanks in advance for any replies.
The Android Runtime (ART) and Dalvik virtual machine use paging and memory-mapping (mmapping) to manage memory. This means that any memory an app modifies—whether by allocating new objects or touching mapped pages—remains resident in RAM and cannot be paged out.
Proportional Set Size (PSS): The number of non-shared pages used by the app and an even distribution of the shared pages (for example, if three processes are sharing 3MB, each process gets 1MB in PSS) Unique Set Size (USS): The number of non-shared pages used by the app (shared pages are not included)
The Heap is used for dynamic memory allocation. To provide a smooth user experience, Android sets a hard limit on the heap size for each running application. The heap size limit varies among devices and is based on how much RAM a device has.
So after some research we found a solution.
But first of all: These methods won't help and either won't these. The methods mentioned in the first post will get you absolutely useless numbers which won't help you at all and may not even be correct (since my galaxy S3 got a much higher number than a nexus 7. But in our tests the nexus 7 could load the same amount or even more textures than the S3).
Then let's move on to our solution - which we are still not sure is the best, but it will work:
It look likes you can keep as many textures in OpenGL as you have free total RAM. Yes total RAM, not heap and not something other related to your app! It's really the amount of free RAM of your whole system, there are NO restrictions!
So once you figure that out you just read out the amount of free RAM you have:
ActivityManager actvityManager = (ActivityManager) mapView.getActivity().getSystemService( Activity.ACTIVITY_SERVICE );
ActivityManager.MemoryInfo mInfo = new ActivityManager.MemoryInfo ();
actvityManager.getMemoryInfo( mInfo );
Log.v("neom","mema " + mInfo.availMem/1024/1024);
Best place to do that is probably in your onSurfaceCreated
method or somethign like that.
The amount of memory you get there is the total free RAM you currently have. Mostly this value is too low, in almost any case you can even allocate more memory than you get there (in our tests we could always allocate about 30%-50% more RAM than the availMem gave us until the app crashed (tested on Nexus 7 (+28%), Galaxy S3 (+36%), Transformer T1 (+57%), Nexus S (+57%))). Reason for this is: Android will free memory from unused stuff, background processes and so on, before it really runs out of memory.
So what does this mean?
You can (almost) safely keep as many "bytes-of-textures" in OpenGL as you have free RAM. For example: Lets say you have 375 MB free RAM and textures which each have a size of 256kb, you could keep about 1500 Textures in OpenGL before you start deleting some of them (with an LRU cache or something like that). You could even keep more, but I think you are pretty safe with this amount.
Sureley you could also get the availmem
more frequently and just fit your cache size or what ever you are doing to this new amount of memory - but I think it suffices if you do it once in onSurfaceCreated
- especially since this will be read out again if you switch to another app and back.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With