Related
I have a problem with using the QNetworkAccessManager in Qt 5.5 on android. Downloading a simple, small graphic file via http GET results in a lot of garbage collection calls and a lockup of the UI during that time. Subsequent GETs work flawlessly and without these GC calls. The code is as follows:
void DownloadManager::downloadFile(QUrl fromUrl, QString toFilePath) {
_currentFilePath = toFilePath;
QNetworkRequest request;
request.setUrl(fromUrl);
qDebug() << "before";
_currentReply = _mgr.get(request);
qDebug() << "after";
connect(_currentReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(downloadError(QNetworkReply::NetworkError)));
connect(_currentReply, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(downloadProgress(qint64,qint64)));
connect(_currentReply, SIGNAL(finished()), this, SLOT(downloadFinished()));
}
DownloadManager is a custom QObject-derived class without any special features that are relevant to the get request. _mgr is a QNetworkAccessManager Object that's allocated during DownloadManagers cTor.
As you can see, this is just a textbook example of a get request, nothing too fancy about it. And as I said: it works, for the most part. Only the first get request ends up like this:
D/ .../downloadmanager.cpp:61 (void DownloadManager::downloadFile(QUrl, QString)): before
D/dalvikvm(13298): GC_CONCURRENT freed 2290K, 25% free 10911K/14407K, paused 2ms+3ms, total 29ms
D/dalvikvm(13298): GC_CONCURRENT freed 501K, 25% free 10884K/14407K, paused 13ms+2ms, total 35ms
D/dalvikvm(13298): GC_CONCURRENT freed 524K, 25% free 10892K/14407K, paused 12ms+3ms, total 36ms
D/dalvikvm(13298): WAIT_FOR_CONCURRENT_GC blocked 6ms
D/dalvikvm(13298): GC_CONCURRENT freed 537K, 25% free 10887K/14407K, paused 2ms+9ms, total 32ms
D/dalvikvm(13298): WAIT_FOR_CONCURRENT_GC blocked 14ms
D/dalvikvm(13298): GC_CONCURRENT freed 840K, 25% free 10899K/14407K, paused 12ms+3ms, total 38ms
D/dalvikvm(13298): WAIT_FOR_CONCURRENT_GC blocked 11ms
D/dalvikvm(13298): GC_CONCURRENT freed 1294K, 25% free 10901K/14407K, paused 2ms+2ms, total 27ms
D/dalvikvm(13298): WAIT_FOR_CONCURRENT_GC blocked 11ms
D/dalvikvm(13298): GC_CONCURRENT freed 1187K, 22% free 11330K/14407K, paused 2ms+2ms, total 30ms
D/dalvikvm(13298): WAIT_FOR_CONCURRENT_GC blocked 15ms
D/dalvikvm(13298): GC_CONCURRENT freed 1459K, 19% free 11919K/14535K, paused 13ms+4ms, total 64ms
D/dalvikvm(13298): WAIT_FOR_CONCURRENT_GC blocked 18ms
D/ .../downloadmanager.cpp:65 (void DownloadManager::downloadFile(QUrl, QString)): after
I simply don't understand what causes that much GC to happen - it takes about a full to one and a half seconds for everything to work out (for a download that should take a split-second and, moreover, be asynchronus and not locking up the UI).
Additional Information:
It is always only the first download that triggers this. Subsequent downloads, even for the exact same file, work flawlessly
It doesn't matter if there's a file at the exact location with the exact name or not. Downloading the file, deleting it, getting back into the application and redownloading it provides the same results - the first get is slow and has the GC, the second works perfectly fine.
I call all that from a QML File, that causes a singleton c++ object to call DownloadManager::downloadFile.
Other than the QML UI, nothing else is running within the application. No heavy data exchanges, no background loading on other threads, nothing.
I'd be thankful for any pointers towards solving this.
I didn't try on Android, but I had the same issue on Windows. Because those are the same symptoms, I would say this is likely the same reason, which is that the implementation is lazily loading some shared library on the first get() call. This is particularly true when using an encrypted connection; in my case I can see in Visual Studio that 19 DLLs are loaded on the first get() call.
One way to work around that is to pre-connect to the server using connectToHost or connectToHostEncrypted, depending on whether you are using an encrypted connection (e.g. HTTPS) or not. I am calling that at application startup, but anytime the UI is idle should be fine. Then subsequent get() calls will all have the same performance, including the first one, since the libraries have been loaded and the connection is already established. I am assuming that connecting to any server will load the libraries.
See https://forum.qt.io/topic/65201/qnetworkaccessmanager-first-get-very-slow/14 for details on the generic error (not specific to Android).
I'm using Picasso to load tons of (relatively small) images inside a BaseAdapter combined with my own implementation of an endless ListView. Basically I'm using almost the simplest setup possible:
Picasso.with(c)
.load(friend.getPhoto_url_200())
.resize(200, 200)
.centerCrop()
.placeholder(R.drawable.default_profile)
.error(R.drawable.default_profile)
.transform(transformation)
.into(holder.imgAva);
AFAIK, Picasso takes care of image caching and recycling on its own. Looking at the logs I see that the amount of memory being freed by GC continuously increases when loading more items (though the amount of RAM used by the application only increases by <3MB when comparing 10 vs 500 loaded items):
D/dalvikvm﹕ GC_FOR_ALLOC freed 481K, 8% free 23093K/24944K, paused 14ms, total 14ms
D/dalvikvm﹕ GC_FOR_ALLOC freed 348K, 7% free 23399K/25104K, paused 12ms, total 12ms
D/dalvikvm﹕ GC_FOR_ALLOC freed 798K, 8% free 23587K/25532K, paused 14ms, total 14ms
D/dalvikvm﹕ GC_FOR_ALLOC freed 415K, 7% free 24053K/25852K, paused 13ms, total 13ms
D/dalvikvm﹕ GC_FOR_ALLOC freed 1761K, 9% free 24153K/26428K, paused 21ms, total 21ms
D/dalvikvm﹕ GC_FOR_ALLOC freed 664K, 9% free 24297K/26428K, paused 18ms, total 18ms
D/dalvikvm﹕ GC_FOR_ALLOC freed 354K, 7% free 25064K/26860K, paused 18ms, total 19ms
D/dalvikvm﹕ GC_FOR_ALLOC freed 1064K, 9% free 25568K/27840K, paused 19ms, total 19ms
D/dalvikvm﹕ GC_FOR_ALLOC freed 1581K, 10% free 25732K/28480K, paused 22ms, total 26ms
D/dalvikvm﹕ GC_FOR_ALLOC freed 1202K, 9% free 26343K/28780K, paused 20ms, total 20ms
D/dalvikvm﹕ GC_FOR_ALLOC freed 1514K, 10% free 26537K/29448K, paused 20ms, total 20ms
D/dalvikvm﹕ GC_FOR_ALLOC freed 1265K, 10% free 26849K/29768K, paused 14ms, total 14ms
D/dalvikvm﹕ GC_FOR_ALLOC freed 1243K, 10% free 27381K/30172K, paused 19ms, total 20ms
D/dalvikvm﹕ GC_FOR_ALLOC freed 1615K, 10% free 27956K/30972K, paused 23ms, total 23ms
D/dalvikvm﹕ GC_FOR_ALLOC freed 1595K, 10% free 28555K/31588K, paused 21ms, total 21ms
D/dalvikvm﹕ GC_FOR_ALLOC freed 2071K, 11% free 29106K/32532K, paused 16ms, total 16ms
D/dalvikvm﹕ GC_FOR_ALLOC freed 1879K, 10% free 29837K/33052K, paused 22ms, total 22ms
D/dalvikvm﹕ GC_FOR_ALLOC freed 2012K, 11% free 30596K/34132K, paused 21ms, total 21ms
D/dalvikvm﹕ GC_FOR_ALLOC freed 2570K, 11% free 31431K/35204K, paused 20ms, total 20ms
D/dalvikvm﹕ GC_FOR_ALLOC freed 3169K, 12% free 32091K/36276K, paused 22ms, total 22ms
At some point I'm also getting a JIT message telling me it's resizing the JIT table to allocate more memory.
In this regard, my questions are:
Can I do anything to further optimize the process or should I leave Picasso handle it on its own?
I did not have the opportunity to test this on a low-end device, the Nexus 5 is a relatively powerful device so I wasn't able to reach the heap limit. How would Picasso behave when it starts running out of memory? Will it delete cached items/decrease the amount of images set into the list ImageViews/do something else or will it just throw an OutOfMemoryError?
are there any general tips that should be considered when using Picasso to load images into a ListView?
Using picasso is a very good choice it handles Disk and memory caching with various expiration policies Images downsampling to the target view size to improve performance and reduce memory usage Batching UI updates to improve UI responsiveness So you normally don't have to worry about memory, but i suggestyou give a shot to the volley lib it's far more better
I'm getting way too many GC_FOR_ALLOC from the dalvikvm.
I'm getting XML from a REST service: in one activity I parse about 100 lines programatically(me) and in the other activity I use the SimpleXML to parse about 200 lines.
In the first one I get 50 GC_FOR_ALLOC.
In the second one I get like 300!! (I can't even post it all, the body makes 29579 characters and it's allowed only 30k)
I've searched and almost everyone complains about gc_for_"M"alloc and not gc_for_"A"lloc.
Is the SimpleXML the problem because the instances created?
I'll post the logcat dump by dalvikvm, maybe the values have some information.
Thank you very much for your help.
12-11 06:13:49.564: D/dalvikvm(6759): GC_FOR_ALLOC freed 362K, 13% free 4116K/4688K, paused 181ms, total 182ms
12-11 06:13:50.074: D/dalvikvm(6759): GC_FOR_ALLOC freed 303K, 13% free 4134K/4708K, paused 142ms, total 142ms
.... repeated many times .....
12-11 06:14:06.254: D/dalvikvm(6759): GC_FOR_ALLOC freed 73K, 13% free 4159K/4768K, paused 53ms, total 53ms
12-11 06:14:06.314: D/dalvikvm(6759): GC_FOR_ALLOC freed 103K, 13% free 4159K/4768K, paused 56ms, total 57ms
12-11 06:14:06.374: D/dalvikvm(6759): GC_FOR_ALLOC freed 29K, 12% free 4203K/4768K, paused 54ms, total 54ms
12-11 06:14:06.424: D/dalvikvm(6759): GC_FOR_ALLOC freed 73K, 13% fre
You can see the most-recently-allocated objects using the DDMS Allocation Tracker (memory debugging docs, old blog post, ddms docs). This will show you what's being allocated and give you a stack trace for the place where the allocation is being performed.
Another blog post describes MAT and other relevant tools, though heap-dump analysis is less useful for this sort of problem because it generally shows you the objects that haven't been freed, and you're more interested in the objects that are being freed.
In Android Dalvik VM, GC_FOR_ALLOC is inovked in object alloc step when dlmalloc footprint space is NOT enough for new or heap->bytesAllocated + n > hs->softLimit. You can set dalvik.system.setTargetHeapUtilization lower for more free heap space.
you can use MAT MAT tutorial
to find how many object are creating and garbage collected. so that youcan optimize your code
If you get that multiple GC_FOR_ALLOC while your app is lagging, there is a big possibility that the bug is in a loop. Check where the line of code starts to trigger the GC then start tracing the code from there. In my experience, I mistyped my inner loop iterator which causes the program to make an infinite loop. I created a bug like this:
for(int i=0; i<list.size(); i++) {
for(int j=i+1 j<list.size(); i++) {
// I mistyped the iterator of integer j with i
// making an infinite loop which triggered the GC.
//appears many times
}
}
I encounter the same problem today.
I find a not ended loop in my code such as while(i < xx), but I not implement the i++ statement in the while body.
So the messages like you meet appeared.
Check your code firstly please.
My log:
D/dalvikvm: GC_FOR_ALLOC freed 549K, 9% free 7878K/8596K, paused 30ms, total 34ms
...freed 539K, 9% free 7888K/8596K, paused 30ms, total 30ms
...freed 1856K, 21% free 8083K/10108K, paused 51ms, total 51ms
...freed 582K, 9% free 7845K/8596K, paused 38ms, total 38ms
Explain:
When your app get memory more limit per app. Dalvik/Ant call garbage collector.
What limits memory for your App decide Dalvik/Ant. As you see for my app Dalvik decide 8596K(double case) and 8083K(one case).
And limits change in runtime.
And you can not be sure when this happens. But you can reduce the likelihood. Decreasing the amount of memory that your application consumes.
PS: Decide when call GC teakes Dalvik/Ant. And you can not be sure when this happens. But you can reduce the likelihood. Decreasing the amount of memory that your application consumes.
PS: In "Monitor android" see tab "Monitors", graphics "Memory". And use buttons: "pause(enabled)", Initiate GC, "Dump Java Heap" "Start Alocation Tracking(very useful)". And use official guide for this:
https://developer.android.com/studio/profile/am-memory.html?utm_source=android-studio.
As far as I understand App must not stop/pause working or crashes when VM call GC.
This is a general question.
In my application the garbage collector is running too often (several times per second) and doesn't free a lot of memory (less than 1Mb).
The thing is, the heap size doesn't grow anymore. It takes about 40Mb, sometimes 60Mb on other phones where the maximum for an application is 128Mb (Galaxy S4) or 196Mb (Nexus 4).
Why does the GC run so often ?
Below is a part of the logcat when the GC runs too often. The application is freezing. I don't even do anything, I just try to zoom a map.
06-07 16:50:52.003: D/dalvikvm(26176): GC_FOR_ALLOC freed 256K, 18% free 60015K/72980K, paused 51ms, total 51ms
06-07 16:50:52.053: D/dalvikvm(26176): GC_FOR_ALLOC freed 256K, 18% free 60016K/72980K, paused 51ms, total 51ms
06-07 16:50:52.113: D/dalvikvm(26176): GC_FOR_ALLOC freed 256K, 18% free 60016K/72980K, paused 52ms, total 52ms
06-07 16:50:52.163: D/dalvikvm(26176): GC_FOR_ALLOC freed 256K, 18% free 60017K/72980K, paused 52ms, total 52ms
06-07 16:50:52.213: D/dalvikvm(26176): GC_FOR_ALLOC freed 256K, 18% free 60017K/72980K, paused 51ms, total 52ms
06-07 16:50:52.273: D/dalvikvm(26176): GC_FOR_ALLOC freed 256K, 18% free 60018K/72980K, paused 51ms, total 51ms
06-07 16:50:52.324: D/dalvikvm(26176): GC_FOR_ALLOC freed 256K, 18% free 60018K/72980K, paused 51ms, total 51ms
06-07 16:50:52.374: D/dalvikvm(26176): GC_FOR_ALLOC freed 256K, 18% free 60019K/72980K, paused 52ms, total 52ms
06-07 16:50:52.434: D/dalvikvm(26176): GC_FOR_ALLOC freed 256K, 18% free 60019K/72980K, paused 53ms, total 53ms
06-07 16:50:52.484: D/dalvikvm(26176): GC_FOR_ALLOC freed 256K, 18% free 60020K/72980K, paused 52ms, total 52ms
06-07 16:50:52.544: D/dalvikvm(26176): GC_FOR_ALLOC freed 256K, 18% free 60020K/72980K, paused 56ms, total 56ms
06-07 16:50:52.594: D/dalvikvm(26176): GC_FOR_ALLOC freed 256K, 18% free 60021K/72980K, paused 52ms, total 52ms
06-07 16:50:52.654: D/dalvikvm(26176): GC_FOR_ALLOC freed 256K, 18% free 60021K/72980K, paused 52ms, total 52ms
06-07 16:50:52.704: D/dalvikvm(26176): GC_FOR_ALLOC freed 256K, 18% free 60022K/72980K, paused 52ms, total 52ms
06-07 16:50:52.754: D/dalvikvm(26176): GC_FOR_ALLOC freed 256K, 18% free 60022K/72980K, paused 52ms, total 52ms
06-07 16:50:52.814: D/dalvikvm(26176): GC_FOR_ALLOC freed 256K, 18% free 60023K/72980K, paused 52ms, total 52ms
06-07 16:50:52.864: D/dalvikvm(26176): GC_FOR_ALLOC freed 256K, 18% free 6023K/72980K, paused 51ms, total 51ms
06-07 16:50:52.924: D/dalvikvm(26176): GC_FOR_ALLOC freed 256K, 18% free 60024K/72980K, paused 55ms, total 56ms
06-07 16:50:52.974: D/dalvikvm(26176): GC_FOR_ALLOC freed 256K, 18% free 60024K/72980K, paused 52ms, total 52ms
06-07 16:50:53.024: D/dalvikvm(26176): GC_FOR_ALLOC freed 256K, 18% free 60025K/72980K, paused 52ms, total 52ms
Your problem is related to how Google Maps Android API works and how much memory is allocated by your application.
40-60 MB might problematic because it takes longer to execute single GCollection. As a side note: I noticed adding 1000 markers takes significantly longer when having 15 MB allocated comapred to when having 5 MB.
In addition to that every call to the Google Play Services APIs is doing IPC, which in turn forces GC according to this answer. It is possible that such IPC calls are done when panning or zooming.
It would be preferable to keep your memory footprint much lower.
The GC runs when it needs to. In general, (even on the DVM) it really does know, way better than you do, when it needs to run. If you frame this problem not as a problem with the GC, but as a problem with your app's memory, it might help you find a solution.
The most likely reason for frequent GCs is that you are nearly out of memory. This could happen, for instance, if you allocate lots of short-lived objects: You allocate them fast, but forget them just as quickly. Every time the GC runs, it successfully recovers enough memory for the app to continue... but just as quickly, you fill memory again.
If this is actually what is happening, then, if you had more memory, as suggested by #parry, you would just delay the problem. GCs would occur less frequently, but take longer to run (because they would collect more garbage). That might be sufficient, but probably not.
Check to see if you are allocating objects in a routine that is called frequently (for instance, your draw routines).
If you believe the GC is acting stupid (quite possible), and that the VM has more memory to spare, then you could try forcing it to increase the heap size by asking for a one off 1/5/10 MB allocation (guarding it with a try-catch for OOME).
This might cause the GC to clean up more on each cycle, or increase the chances for a full GC to occur.
Another heuristic, which works on a PC, is calling System.GC() x times in a loop to trigger a full GC.
All in all, I came across it myself and it sucks.
I've got a relatively light weight app that seems to be using large portions of heap memory (in my opinion) and it doesn't shrink after garbage collection.
I haven't been able to identify any memory leaks by using the Eclipse Memory Analyzer. My knowledge of this tool is though very limited.
Snippet from LogCat:
(Note that this is only a small snippet from a log dump. The LogCat seems to output garbage collection messages almost no matter what I do inside my app, continously. The amount of free heap remains relatively stable though, indicating (to me) that there is no actual memory leak?)
01-22 17:04:51.672: D/dalvikvm(16274): GC_CONCURRENT freed 721K, 10% free 8074K/8968K, paused 4ms+7ms, total 33ms
01-22 17:04:53.742: D/dalvikvm(16274): GC_CONCURRENT freed 523K, 12% free 7977K/8968K, paused 4ms+5ms, total 29ms
01-22 17:04:54.012: D/dalvikvm(16274): GC_CONCURRENT freed 457K, 12% free 7941K/8968K, paused 3ms+2ms, total 29ms
01-22 17:04:56.432: D/dalvikvm(16274): GC_CONCURRENT freed 237K, 10% free 8116K/8968K, paused 2ms+2ms, total 22ms
01-22 17:04:58.632: D/dalvikvm(16274): GC_CONCURRENT freed 445K, 10% free 8094K/8968K, paused 3ms+3ms, total 33ms
01-22 17:05:00.332: D/dalvikvm(16274): GC_CONCURRENT freed 499K, 11% free 8013K/8968K, paused 1ms+10ms, total 33ms
01-22 17:05:00.582: D/dalvikvm(16274): GC_CONCURRENT freed 487K, 12% free 7916K/8968K, paused 3ms+6ms, total 38ms
01-22 17:05:02.382: D/dalvikvm(16274): GC_CONCURRENT freed 223K, 10% free 8107K/8968K, paused 3ms+3ms, total 23ms
01-22 17:05:03.882: D/dalvikvm(16274): GC_CONCURRENT freed 436K, 10% free 8107K/8968K, paused 9ms+12ms, total 76ms
01-22 17:05:05.392: D/dalvikvm(16274): GC_CONCURRENT freed 528K, 11% free 8059K/8968K, paused 2ms+3ms, total 35ms
01-22 17:05:06.962: D/dalvikvm(16274): GC_CONCURRENT freed 489K, 11% free 7998K/8968K, paused 4ms+3ms, total 32ms
01-22 17:05:07.212: D/dalvikvm(16274): GC_CONCURRENT freed 487K, 12% free 7928K/8968K, paused 3ms+3ms, total 29ms
01-22 17:05:08.832: D/dalvikvm(16274): GC_CONCURRENT freed 226K, 10% free 8094K/8968K, paused 3ms+3ms, total 22ms
01-22 17:05:12.152: D/dalvikvm(16274): GC_CONCURRENT freed 453K, 10% free 8080K/8968K, paused 4ms+3ms, total 48ms
The above is a result of "heavy use", involving spamming on buttons and changing orientation several times. My concern is the fact that only ~10% of the heap seems to be free/left for further expansions.
For your information, the XML file representing the current fragment's layout (at the time of the above output) is a ScrollView with a TableLayout inside, consisting of about 25 TableRow elements, perhaps this is the cause for such large hogging of heap memory?
Is this something to worry about at all?
Please let me know if you prefer to look at some of my code. Thanks in advance.
Update:
The app is basically just one Activity containing two fragments. One of said fragments get swapped out with other fragments based on user interaction.
Think of it as a typical Menu-Content app (like the default Android Contacts app). MenuFragment (Contacts list) on the left and some ContentFragment (Contacts details) on the right. So far there is not too much functionality
involved except for setting up the UI behavior. There is nothing happening in the background, no saving of states or similar. I've basically focused on making sure that
the correct fragment shows up when I select an item from my MenuFragment, that the correct layouts are drawn when a fragment launches, and that the correct fragment
is displayed when the user presses the back button.
The heap will adjust it's size automatically based upon the needs of your app. Small heaps are faster on the GC so Android will not start you out with a 64 MB heap if you don't need it. While you're app is using a lot of your current heap, the heap is extremely small for an Android 4.x app. A bare bones 4.x app alone will use up 7Mb. From what I see, you're fine.