1

I'm participating in development of an Android application that uses quite heavy native library (~20Mb). Actual problem is that GC is working very frequently to resume some (but not too much) memory. Multiple times per second.

04-10 12:16:05.391  18940-18951/com.some.demo D/dalvikvm﹕ GC_FOR_ALLOC freed 6120K, 29% free 31708K/44359K, paused 20ms, total 20ms
04-10 12:16:05.501  18940-18951/com.some.demo D/dalvikvm﹕ GC_FOR_ALLOC freed 6121K, 29% free 31708K/44359K, paused 23ms, total 23ms
04-10 12:16:05.601  18940-18951/com.some.demo D/dalvikvm﹕ GC_FOR_ALLOC freed 6120K, 29% free 31708K/44359K, paused 23ms, total 23ms
04-10 12:16:05.702  18940-18951/com.some.demo D/dalvikvm﹕ GC_FOR_ALLOC freed 6120K, 29% free 31708K/44359K, paused 25ms, total 25ms
04-10 12:16:05.802  18940-18951/com.some.demo D/dalvikvm﹕ GC_FOR_ALLOC freed 6120K, 29% free 31708K/44359K, paused 28ms, total 28ms
04-10 12:16:05.902  18940-18951/com.some.demo D/dalvikvm﹕ GC_FOR_ALLOC freed 6120K, 29% free 31708K/44359K, paused 28ms, total 28ms
04-10 12:16:06.002  18940-18951/com.some.demo D/dalvikvm﹕ GC_FOR_ALLOC freed 6120K, 29% free 31708K/44359K, paused 26ms, total 26ms
04-10 12:16:06.122  18940-18951/com.some.demo D/dalvikvm﹕ GC_FOR_ALLOC freed 6120K, 29% free 31708K/44359K, paused 41ms, total 41ms

In Android Device Monitor (Heap tab) tool I can see that >25 MB is allocated by 1-byte array (byte[], boolean[]), other parts consuming much lower heap. In Allocation Tracker I can see a lot of lines with 3133456 byte[] for dalvik.system.NativeStart.

It raises a question: does Android load all native library into memory or am I doing something wrong? I need some good explanation how Android deals with native libraries.

If there is no really effective way to reduce heap space taken by native library (removing dependency isn't an option, because not only Android uses it), then is there any other way to lower frequency of GC?

EDIT: Adding images to provide more information.

Heap space: Heap

Memory allocation: Allocation

trincot
  • 317,000
  • 35
  • 244
  • 286
Igor K
  • 470
  • 6
  • 10
  • 1
    If you want low frequency of GC, you will have to update native code. We cannot control GC frequency, it depends on our code/logic – Androider Apr 10 '15 at 11:18
  • 1
    You may be looking in the wrong direction - native code's storage is normally independent of the Java heap that you are monitoring, and the size of the code itself is not part of that either. But native code can call functions to allocate objects on the Java heap for jni interchange, or the Java side can do that, and either can hold onto a reference which prevents GC. So look at your java code and the java/native interaction, rather than the internal core of the native code. – Chris Stratton Apr 10 '15 at 12:23
  • @pokerface I am thinking you are right, but I need some documentation on this, exactly how native library of application is loaded into memory. – Igor K Apr 10 '15 at 13:44
  • @ChrisStratton, thanks you for the answer, but I don't understand your suggestion where to look for an improvement. Application main functionality is in dependency (native library) and application uses it all the way. GC is called multiple times per second, this situation I want to avoid. java/native interaction is quite simple: loading native library in static block with System.loadLibrary, creating and obtaining instance of class that wraps native methods. – Igor K Apr 10 '15 at 13:56
  • Many Android API interactions you can do involve jni, even if it is done behind the scenes of a C API that you are calling - look at the objects you are using when interacting with Android APIs. As I said before, the native library itself is not on the Java heap, nor do normal C/C++ type allocations end up there. – Chris Stratton Apr 10 '15 at 14:25

1 Answers1

-1

I'm posting references that can be useful for those who will experience the same problems and lack of information on topic.

I've found an answer here https://stackoverflow.com/a/11312145/955107 that states: A GC_FOR_ALLOC is by itself not a sign of a problem in your application however:

  • Android applications start with a small heap which grows (up to a point) when applications require more and more memory, and a GC_FOR_ALLOC is done before increasing the size of the heap. In this case GC_FOR_ALLOC is perfectly normal.
  • If you allocate memory faster than the concurrent GC has time to free it up, GC_FOR_ALLOC is inevitable. And there's nothing inherently wrong with allocating memory faster than the concurrent GC can free up memory.

Also a very useful source of information is video by Patrick Dubroy. It gave me more understanding what is happening in my application and what I need to analyze in my code: Google I/O 2011: Memory management for Android Apps. Special attention to questions and answers on 53 minute 5 seconds and 55 minute 42 seconds.

Community
  • 1
  • 1
Igor K
  • 470
  • 6
  • 10
  • What you really understood from those answers? The presenter kept saying either "I don't know" or "I don't have any advice on that" – Farid Aug 08 '22 at 13:52