Поговорим об основных принципах управления памятью платформой Android.
Рассмотрим механизм работы сборщика мусора, отличие работы в виртуальных машинах Dalvik и ART.
Узнаем о возможных причинах возникновения утечек памяти и инструментах их обнаружения.
Будет представлен ряд практических советов о том, как не допустить появление утечек памяти при разработке приложения.
4. Android Memory Management
● Each app process is forked from an existing process
called Zygote
● No swap space
● Virtual Address Space (Memory management unit)
● Paging and Memory-Mapping (mmapping)
● Process space limitation
5. Sharing Memory
● Binder IPC Driver
● Android shares the same dynamic RAM across
processes using explicitly allocated shared memory
regions (ashmem)
● Most static data is mmapped into a process (VM code,
app resources, native code)
6. Application Memory Restrictions
● Isolated in process
● Hard limit heap size
● Heap size limit varies between devices
● Low-Memory Killer (Proportional Set Size)
ActivityManager.getMemoryClass()
ActivityManager.getLargeMemoryClass()
13. ART GC Enhancement
● Enumerates all allocated objects and marks all reachable objects in
only one pause while Dalvik’s GC pauses twice
○ enumeration phase performed by application
○ pre-cleaning technique
● Parallelization
● Lower total GC time (cleaning up recently-allocated)
● Compacting GC merges freed-up single blocks in one location of
memory
(Still in development by Android Open-Source Project)
16. ● Memory leak: situation where some objects are not used by
application any more, but GC fails to recognize them as unused
● Memory consumption increases -> Degradation in performance
● GC does not prevent leaks!
Memory Leaks
17. How to detect?
● Huge memory consumption in Android Studio Memory Monitor
● Frequent GC calls in LogCat
● App crashes with an OutOfMemmoryError (OOM)
D/dalvikvm: <GC_Reason> <Amount_freed>, <Heap_stats>, <External_memory_stats>, <Pause_time>
07-02 15:56:14.275: D/dalvikvm(30615): GC_FOR_ALLOC freed 4442K, 25% free 20183K/26856K, paused 24ms, total 24ms
07-02 15:56:16.785: I/dalvikvm-heap(30615): Grow heap (frag case) to 38.179MB for 8294416-byte allocation
07-02 15:56:17.225: I/dalvikvm-heap(30615): Grow heap (frag case) to 48.279MB for 7361296-byte allocation
07-02 15:56:17.625: I/Choreographer(30615): Skipped 35 frames! The application may be doing too much work on its main thread.
07-02 15:56:19.035: D/dalvikvm(30615): GC_CONCURRENT freed 35838K, 43% free 51351K/89052K, paused 3ms+5ms, total 106ms
I/art: <GC_Reason> <GC_Name> <Objects_freed>(<Size_freed>) AllocSpace Objects, Large_objects_freed>
(<Large_object_size_freed>) <Heap_stats> LOS objects, <Pause_time(s)>
07-02 16:00:44.531: I/art(198): Explicit concurrent mark sweep GC freed 700(30KB) AllocSpace objects, 0(0B) LOS objects, 792% free,
18MB/21MB, paused 186us total 12.763ms
07-02 16:00:44.545: I/art(198): Explicit concurrent mark sweep GC freed 7(240B) AllocSpace objects, 0(0B) LOS objects, 792% free,
18MB/21MB, paused 198us total 9.465ms
07-02 16:00:44.554: I/art(198): Explicit concurrent mark sweep GC freed 5(160B) AllocSpace objects, 0(0B) LOS objects, 792% free,
18MB/21MB, paused 224us total 9.045ms
23. ● Do not keep long-lived references to an Activity, Context, View, Drawable...
● Avoid non-static inner classes in an activity if you don’t control their life cycle
● Avoid mutable static fields
● Use Weak References
● Try to not have long living objects
● Use as much as possible application Context instead of Activity
● Remember to call unregisterReceiver() after calling registerReceiver()
● Implement cancellation policies for background threads
● Use LeakCanary in the QA cycle
● Keep an eye on the heap while the app is running
● Don’t assume GC will clean up all for you!
● Search for memory leaks even when things aren't failing!
How to avoid Memory Leaks?
24. ● Use bitmaps with correct resolution
● Recycle the bitmaps more often, instead of just onDestroy()
● Send large files to server by chunks
● Avoid creating unnecessary objects
● Check the available heap of your application
● Coordinate with the system by implementing onTrimMemory() callback
● External libraries should be used carefully
● Use Proguard and zipalign
How to avoid OutofMemoryError?