Skip to content
Go back

Why Android Apps Lag: Understanding Garbage Collection and Main Thread Performance

Efficient memory management is crucial for building smooth and responsive Android applications. One of the key players in this process is the Garbage Collector (GC). But how does GC work, and why can it sometimes cause our app to lag? Let’s break it down with simple examples and diagrams.


Memory Allocation Example

Imagine our app has a total memory limit of 50MB. We can visualize this as a grid with 10 columns and 5 rows, where each cell represents 1MB.

Diagram 1: Initial Memory Allocation

1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
Total: 50MB

Suppose we launch our application and it takes 5MB. Then, we open Activity 1 (10MB) and Activity 2 (10MB):

Application (5MB) + Activity 1 (10MB) + Activity 2 (10MB) = 25MB

Killing Activities and Memory Usage

Now, let’s say we kill Activity 1 and Activity 2 and open Activity 3 (10MB):

Application (5MB) + Activity 3 (10MB) = 15MB

But, the memory used by Activity 1 and Activity 2 (20MB) is still not immediately freed. This is where the Garbage Collector comes in.

Diagram 2: Memory After Killing Activities

A A A A A 1 1 1 1 1
1 1 1 1 1 2 2 2 2 2
2 2 2 2 2 3 3 3 3 3
3 3 3 3 3 - - - - -
- - - - - - - - - -

A = App, 1 = Activity 1, 2 = Activity 2, 3 = Activity 3


How Garbage Collector (GC) Works

The GC periodically checks memory blocks to see if they are still in use. If not, it frees them up. In our example, the 20MB used by the killed activities is now unnecessary, so GC should remove it.

Diagram 3: After GC Cleans Up

A A A A A - - - - -
- - - - - 3 3 3 3 3
3 3 3 3 3 - - - - -
- - - - - - - - - -
- - - - - - - - - -
Unused memory blocks are collected by GC.

Why Does an Android App Lag?

Android apps are expected to refresh the UI every 16ms (to achieve 60 frames per second). The main thread (UI thread) is responsible for drawing the UI and handling user interactions.

If a task (like onCreate() or GC) takes too long (say, 26ms), the main thread is blocked, and the UI cannot update in time. This causes dropped frames and visible lag.

Diagram 4: Frame Timing and Dropped Frames

Time:  |----16ms----|----16ms----|----16ms----|----16ms----|
Draw:  |   Draw     |   Draw     |   Draw     |   Draw     |

If a task takes 26ms:
Time:  |----16ms----|------26ms------|----16ms----|
Draw:  |   Draw     |  Dropped Frame |   Draw     |

Main Reasons for App Lag

  1. Frequent GC Runs:
    When our app uses a lot of memory, GC runs more often, sometimes on the main thread, causing UI freezes.

  2. Heavy Work on Main Thread:
    Long-running tasks (like network calls or heavy computations) block the main thread, delaying UI updates.

How to Avoid Lag


Share this post on:

Previous Post
Why largeHeap Is Bad for Android Apps: Performance & Memory Explained
Next Post
What Happens When an Android App Launches: Behind the Scenes of Memory Allocation