Module 17 of 20

Performance, Memory & Optimization

Optimize Android app performance, profile memory usage, detect leaks, optimize layout rendering, and decrease APK size.

Module 17: Performance, Memory & Optimization

Learning Objectives

By the end of this module, you’ll understand:

  • Android memory architecture
  • Heap vs Stack
  • Object allocation
  • Garbage Collection (GC)
  • Memory leaks
  • Context leaks
  • Activity leaks
  • LeakCanary
  • ANRs (Application Not Responding)
  • StrictMode
  • Rendering pipeline
  • Choreographer
  • VSync
  • Frame rendering
  • Jank
  • RecyclerView/Compose performance
  • Startup optimization
  • R8 & ProGuard
  • Baseline Profiles
  • Profiling tools
  • Battery optimization
  • Performance best practices

Part 1 — What is Performance?

Performance isn’t one thing.

It’s a combination of:

Performance

├── Startup Time
├── UI Smoothness
├── Memory Usage
├── CPU Usage
├── Battery Usage
├── Network Efficiency
└── Storage Efficiency

An app that loads fast but drains the battery is not a performant app.


Part 2 — Memory Architecture

Every Android app receives a memory space called the Heap.

Conceptually:

Android App

└── JVM / ART Heap

      ├── User Objects
      ├── Strings
      ├── Lists
      ├── Images
      └── ViewModels

Whenever you write:

val user = User()

Memory is allocated on the heap.


Stack vs Heap

One of the most important computer science concepts.

Stack

Stores:

  • Function calls
  • Local primitive values
  • References to objects

Example:

fun login() {
    val name = "Alice"
}

During execution:

Stack

login()



name reference

Very fast.

Automatically cleaned when the function returns.


Heap

Stores:

User()

Bitmap()

ArrayList()

Repository()

RoomDatabase()

Objects stay alive until nothing references them.


Analogy

Imagine a library.

Stack:

Reading Desk



Temporary Books



Return When Finished

Heap:

Book Storage



Books Stay Until Removed

Part 3 — Object Allocation

Every object requires memory.

Example:

repeat(100000) {
    User()
}

This creates:

100,000 Objects

Allocation isn’t free.

Modern devices are fast, but excessive allocations:

  • Increase GC pressure
  • Reduce performance
  • Increase battery usage

Part 4 — Garbage Collection (GC)

Who frees unused objects?

Not you.

Android (ART runtime) uses Garbage Collection.

Example:

User



No References



Garbage Collector



Memory Reclaimed

You never manually call free() like in C.


How GC Works

Imagine:

Activity



ViewModel



Repository



User

If:

Repository



null

and nothing else references User:

GC eventually removes it.


Stop-the-World

Some GC phases pause application threads briefly.

Conceptually:

App Running



GC Starts



Pause



Cleanup



Resume

Modern ART has concurrent and generational collectors that minimize pauses, but frequent allocations can still contribute to frame drops (jank).


Part 5 — Memory Leaks

A memory leak occurs when:

Objects are no longer needed but are still referenced, preventing the GC from reclaiming them.

Example:

Activity Destroyed



Still Referenced



GC Cannot Remove It

Memory usage grows.

Eventually:

OutOfMemoryError

Common Leak Example

Imagine:

Activity



Static Variable



Activity

The static reference keeps the Activity alive.

Even after rotation.

Leak.


Context Leaks

One of the most common Android interview topics.

Suppose:

object ImageLoader {
    lateinit var context: Context
}

Then:

context = activity

Now:

Singleton



Activity Context

Activity cannot be garbage collected.

Huge leak.


Correct:

Singleton



Application Context

Application context lives for the lifetime of the app and is safe for long-lived objects when appropriate.


Activity Leaks

Imagine rotation:

Activity A



Destroyed



Activity B Created

If A is still referenced:

Now both exist.

Rotate 20 times.

Twenty leaked Activities.


Fragment Leaks

A common mistake:

Fragment



View Binding



View Destroyed



Binding Still Referenced

The Fragment outlives its view.

Always clear view bindings in onDestroyView() when using the View system.


Part 6 — LeakCanary

Finding leaks manually is difficult.

LeakCanary automatically detects:

Destroyed Activity



Still Alive



Leak Report

It provides:

  • Leak trace
  • Reference chain
  • Suspected cause

It’s one of the most valuable debugging tools for Android.


Part 7 — ANR (Application Not Responding)

One of Android’s worst user experiences.

Imagine:

User Clicks



Nothing Happens



5 Seconds



ANR Dialog

Typically caused by blocking the main thread.

Examples:

  • Database query
  • Network request
  • Large file read
  • Heavy computation

Main Thread Rule

The UI thread should:

Handle Input



Layout



Draw



Animations

Not:

Download 500 MB



Parse Huge JSON



Compress Images

Those belong on background threads or coroutines.


Part 8 — StrictMode

StrictMode helps detect bad behavior during development.

Examples:

  • Disk access on the main thread
  • Network access on the main thread
  • Resource leaks

Think of it as a development-time safety net.


Part 9 — Rendering Pipeline

One of the most important Android concepts.

Suppose:

User scrolls.

Pipeline:

Input



Measure



Layout



Draw



GPU



Display

This repeats for every frame.


VSync

Displays refresh at fixed intervals.

For a 60 Hz display:

Every 16.67 ms



New Frame

120 Hz?

Every 8.33 ms

Miss the deadline:

Frame skipped.

User notices stutter.


Choreographer

The Android Choreographer coordinates frame rendering with VSync.

Conceptually:

VSync Signal



Choreographer



UI Updates



Render Frame

It schedules rendering work so frames align with the display refresh.


Part 10 — Frame Budget

At 60 Hz:

You have approximately:

16.67 ms

to:

  • Run animations
  • Process input
  • Measure
  • Layout
  • Draw

Finish within the budget:

16 ms



Smooth

Take:

40 ms

Dropped frame.


Jank

Jank is:

Noticeable stuttering caused by missing frame deadlines.

Reasons:

  • Heavy recomposition
  • Expensive layout
  • Large bitmap decoding
  • Main-thread database work
  • Excessive allocations triggering GC

Part 11 — RecyclerView Performance

RecyclerView is fast because it:

Recycles Views

Instead of:

1000 Items



1000 Views

It keeps only the visible views (plus a small cache) and reuses them.


Optimization tips:

  • Use DiffUtil
  • Stable IDs when appropriate
  • Avoid expensive work in onBindViewHolder()
  • Load images asynchronously

Compose Performance

Compose doesn’t recycle views.

Instead it relies on:

State



Recomposition



UI Update

Performance depends on minimizing unnecessary recompositions.

Key concepts:

  • Stable state
  • Immutable models
  • remember
  • derivedStateOf
  • Lazy layouts
  • Correct use of keys

Part 12 — Startup Optimization

Users judge apps quickly.

Cold start:

Tap Icon



Process Starts



Application Created



Activity Created



First Frame

Avoid:

  • Heavy work in Application
  • Large synchronous initialization
  • Blocking I/O during startup

Initialize expensive features lazily where possible.


Baseline Profiles

One of the biggest modern Android performance improvements.

Normally:

Install App



Runtime Optimizes Code



Eventually Faster

With Baseline Profiles:

Install App



Critical Code Already Optimized



Fast Immediately

They improve startup and common user journeys by guiding ahead-of-time compilation.


Part 13 — R8 & ProGuard

Release builds differ from debug builds.

R8 performs:

  • Code shrinking
  • Dead code removal
  • Optimization
  • Obfuscation

Result:

Smaller APK



Less Download



Faster Install

Obfuscation also makes reverse engineering more difficult.


Part 14 — Images

Large bitmaps consume a lot of memory.

Example:

4000 × 3000 Image

Huge allocation.

Best practices:

  • Resize to display size
  • Prefer image loading libraries (Coil, Glide)
  • Avoid loading full-resolution images unnecessarily

Part 15 — Profiling

Android Studio Profiler helps inspect:

CPU

Memory

Network

Energy

Instead of guessing, you measure.

Performance engineering is driven by evidence.


CPU Profiler

Shows:

Functions



Execution Time

Useful for identifying expensive operations.


Memory Profiler

Shows:

Heap



Allocations



Leaks

Helps detect:

  • Growing memory
  • Excessive allocations
  • Leak patterns

Network Profiler

Shows:

  • Requests
  • Response sizes
  • Timing
  • Frequency

Useful for spotting unnecessary API calls.


Energy Considerations

Battery usage depends on:

  • CPU
  • GPS
  • Camera
  • Sensors
  • Network
  • Wake locks

Efficient apps:

  • Batch work
  • Avoid unnecessary polling
  • Respect WorkManager constraints
  • Minimize background activity

Part 16 — Performance Mindset

Imagine loading a feed.

Bad:

Button



Network



Huge JSON



Parse on Main Thread



Freeze UI

Better:

Network



Background Parsing



Room



Flow



Compose

Notice how everything you’ve learned contributes to performance.

Architecture influences efficiency.


Complete Performance Pipeline

User Scrolls


Input Event


Compose / RecyclerView


Measure


Layout


Draw


GPU


Display


16.67 ms Deadline

Every stage matters.


Common Mistakes

❌ Performing network requests on the main thread

Always use coroutines or asynchronous APIs.


❌ Keeping Activity references in singletons

Prefer the Application context when a long-lived context is required.


❌ Loading full-size images unnecessarily

Scale images to the display size and use an image loading library.


❌ Allocating objects inside tight loops or frequently called rendering code

Unnecessary allocations increase GC activity.


❌ Ignoring profiling tools

Measure first.

Optimize second.


❌ Optimizing too early

Follow the classic advice:

Make it correct → Make it measurable → Make it fast.

Premature optimization often complicates code without delivering meaningful improvements.


Mental Model

Imagine a restaurant kitchen.

Customer Order


Chef


Cook


Plate Food


Serve

If one station becomes slow:

Everyone waits.

Android rendering works similarly.

A bottleneck in any stage—layout, drawing, image decoding, or GC—can delay the entire frame.


Best Practices

  • Keep the main thread responsive.
  • Minimize unnecessary object allocations.
  • Avoid memory leaks by respecting lifecycle boundaries.
  • Profile before optimizing.
  • Use LeakCanary during development.
  • Enable StrictMode to catch bad practices early.
  • Keep startup work minimal.
  • Use Baseline Profiles and R8 in release builds.
  • Load and cache images efficiently.
  • Design for smooth rendering, not just correct rendering.

Interview Questions

  1. What is the difference between the stack and the heap?
  2. How does Garbage Collection work in Android?
  3. What is a memory leak?
  4. Why can storing an Activity in a singleton cause a leak?
  5. What is an ANR, and what typically causes it?
  6. What is the 16.67 ms frame budget?
  7. What is jank?
  8. How does RecyclerView achieve good performance?
  9. What are Baseline Profiles, and why are they useful?
  10. How would you investigate a slow or memory-hungry Android app?

Module 17 Summary

You now understand the foundations of Android performance engineering:

  • Heap stores objects; the stack stores execution state.
  • Garbage Collection automatically reclaims unreachable objects.
  • Memory leaks occur when objects remain referenced after they should be released.
  • LeakCanary and StrictMode help detect common performance issues.
  • ANRs usually result from blocking the main thread.
  • The rendering pipeline has a strict frame budget (16.67 ms at 60 Hz).
  • RecyclerView and Compose optimize rendering using different models.
  • R8 and Baseline Profiles improve release performance.
  • Profilers provide the data needed to make informed optimizations.

Most importantly, you’ve learned that performance isn’t a single feature—it’s the outcome of good architecture, efficient memory management, responsive UI design, and evidence-based optimization.


Next Module: Security (Android Security, Authentication, Encryption & Secure App Design)

Module 18 explores how to build applications that are secure by design, not just functional.

We’ll cover:

  • Android’s security model and application sandbox
  • Permissions and runtime permission flow
  • Authentication vs authorization
  • Secure token storage
  • Android Keystore System
  • Encryption fundamentals
  • Biometric authentication
  • Network security configuration
  • Certificate pinning
  • Protecting against reverse engineering
  • Root detection concepts
  • OWASP Mobile Top 10
  • Secure coding practices
  • Play Integrity API (conceptual overview)

This module completes another critical pillar of professional Android development: building apps that protect user data and resist common attacks.