Explain generational GC in ART and why onDraw must avoid allocations

ART generational GC and onDraw allocation hazards.
Covers young-gen nursery, mark-sweep fallback, and why a 5-10ms GC pause misses 16ms frame deadline.
Blaming GC without linking allocation to frame timing.
What's really being asked
This question probes whether you understand ART's generational garbage collector and how it interacts with real-time UI rendering. The interviewer wants to see that you know memory allocation is not free on Android, that the UI thread has a hard 16.6 millisecond frame budget at 60 frames per second, and that custom drawing code is a common source of allocation-driven jank. It also tests whether you can distinguish between minor young-generation collections and full heap collections, and whether you understand that concurrent garbage collection still introduces pauses and CPU contention.
The full answer
First, explain that ART uses a generational heap with a young generation nursery for short-lived objects and an old generation for longer-lived data. Second, describe how minor GCs on the young generation are typically fast but are still stop-the-world events that pause all threads. Third, connect onDraw to frame timing: because onDraw is invoked every frame, even small allocations like new Rect or new Paint create a high-frequency garbage stream that rapidly fills the nursery, triggering repeated minor GCs or premature promotion to the old generation. Fourth, quantify the impact: a 5 to 10 millisecond GC pause directly consumes a third to two-thirds of the 16.6 millisecond frame budget, virtually guaranteeing a missed vsync and a dropped frame. Fifth, add nuance by noting that ART's concurrent GC reduces pause times but does not eliminate them, and that avoiding allocations in onDraw removes the root cause rather than relying on the collector to keep up.
The mistakes people make
A major red flag is claiming that modern concurrent GC makes allocation-free drawing unnecessary. Another is jumping straight to object pooling without first explaining generational behavior or the frame budget. Some candidates blame GC generically without tying allocation rate to the 16.6 millisecond deadline, or assert that Kotlin's immutability makes zero allocation impossible, which ignores field-level reuse and canvas API design.
What usually comes next
The interviewer may ask how you would profile this in production, which calls for Systrace or the Android Studio Memory Profiler to correlate GC events with frame drops. They might ask how this principle extends to RecyclerView binding or Compose recomposition. A deeper variant asks how object pools interact with generational collection, which touches on old-generation fragmentation and finalizers.
A concrete example
Imagine a custom line chart that allocates a new Paint object inside onDraw for every grid line. At 60 frames per second with 10 lines, that is 600 Paint allocations every second. Each Paint holds native resources, so the young generation saturates within a few frames, causing a 3 to 5 millisecond minor GC pause every few hundred milliseconds. During a fling, stress promotes objects to the old generation, triggering a concurrent mark-sweep phase that stalls the UI thread for 15 milliseconds and drops two consecutive frames. The correct fix is to define the Paint as a final field, configure it once, and reuse it across draw calls, bringing allocations in onDraw to zero.
Interview question
Why do repeated object allocations inside onDraw commonly cause dropped frames despite ART's generational garbage collector?
- a.Because ART's concurrent collector eliminates GC pauses, so jank must come from CPU contention instead
- b.Because the allocation rate rapidly fills the young generation nursery, triggering repeated stop-the-world minor GCs that consume much of the 16.6ms frame budgetCorrect
- c.Because minor GCs on the young generation run concurrently with the UI thread and never pause rendering
- d.Because each new Paint or Rect object immediately initiates a 15ms full-heap mark-sweep collection
Why? this is the answer
Per-frame allocations create a high-frequency garbage stream that saturates the nursery, causing repeated stop-the-world minor GCs that eat 5-10ms of the 16.6ms budget. Option A is a red-flag misconception: the card explicitly states concurrent GC reduces but does not eliminate pauses, so avoiding allocations removes the root cause.
Just read this? Test yourself on what you have been reading.
Read the original → developer.android.com
- #android
- #performance
- #garbage-collection
- #memory
- #custom-views
You just looked this up. Could you explain it out loud?
That is the part interviews actually test. Tezvyn takes questions like this one and gives you what the interviewer is really checking, the answer that lands, and the mistake that ends the conversation, in the four minutes before your next meeting.
The iPhone app is on the way
We are building it. Until it lands, nothing here is held back from you: every interview card, your saved cards, streaks and the job board all work in Safari, plus hundreds of free practice quizzes of thirty questions each. Sign in and it all carries over to the app the day it arrives.
Want it as an icon? Tap Share at the bottom of Safari, then Add to Home Screen. It opens full screen and the cards you have read stay available offline.
We are hiring for this. Open roles that interview on android — each one lists the topics its interview covers.
See open roles