Ang awtomatikong pamamahala ng memorya sa pamamagitan ng paglilinis ng basura ay ang pangunahing mekanismo ng platform ng Android, batay sa virtual machine na ART. Ayon sa Google Android Documentation, 2026, pinalalaya ng tagapaglinis ng basura ang developer mula sa manu-manong pamamahala ng memorya, awtomatikong tinatanggal ang mga object na wala nang mga reference. Kung walang GC, ang bawat paglalaan ng object ay mangangailangan ng tahasang pagtawag sa free o delete, na sa Java ecosystem na may milyun-milyong object bawat segundo ay pisikal na imposible.
Mga Pangunahing Punto
Garbage Collection (GC) — ay isang awtomatikong proseso ng pagtuklas at pagpapalaya ng memorya na inookupahan ng mga object na hindi na ginagamit ng programa. Sa konteksto ng mobile development, ang GC ay inilalapat sa platform ng Android sa pamamagitan ng virtual machine na ART, pati na rin sa standard na Java Virtual Machine.
Hindi tulad ng mga wika na may manu-manong pamamahala ng memorya (C, C++), kung saan ang programmer ay dapat tahasang tumawag ng free o delete, ganap na inaako ng GC ang gawain ng pagsubaybay sa lifecycle ng mga object. Gumagawa ang developer ng mga bagong object sa pamamagitan ng operator na new, at tinutukoy ng tagapaglinis ang sandali kung kailan ang isang object ay nagiging hindi maabot — ibig sabihin, wala nang natitira pang aktibong reference dito.
Pangunahing sukatan ng kahusayan ng GC — oras ng paghinto (pause time) at throughput. Ang paghinto ay ang panahon kung kailan sinuspinde ang pagpapatakbo ng application para isagawa ang paglilinis. Sa mobile na kapaligiran, ang mga paghinto na mas mahaba sa 8–16 millisecond ay nakikita bilang mga nalaktaw na frame (jank).
Ayon sa datos ng Google I/O 2019, binawasan ng ART sa Android 10 ang tipikal na GC pause sa 2–4 ms, na 70% na mas mababa kumpara sa Dalvik sa Android 4.4. Gayunpaman, ang hindi tamang paghawak ng memorya — madalas na paglalaan ng object sa mga loop, paggawa ng mga pansamantalang instance nang hindi kinakailangan — ay nananatiling pangunahing dahilan ng mga problema sa performance.
Lahat ng implementasyon ng GC sa Java at Android ay batay sa ilang pangunahing algorithm, na pinagsama upang makamit ang balanse sa pagitan ng oras ng paghinto at pagkakumpleto ng paglilinis. Ang pag-unawa sa mga algorithm na ito ay kinakailangan para sa pagsulat ng GC-friendly code.
Mark-and-Sweep — ang pinakasimpleng algorithm na gumagana sa dalawang yugto. Sa yugto ng Mark, tinatahak ng tagapaglinis ang graph ng object, simula sa mga root reference (root set) — mga lokal na variable, static field, stack ng thread. Bawat naaabot na object ay minamarkahan ng live na flag. Sa yugto ng Sweep, tinatahak ng tagapaglinis ang buong heap at pinalalaya ang memorya ng mga hindi namarkahang object.
Kakulangan — pagkakapira-piraso ng memorya: pagkatapos ng Sweep, ang mga libreng lugar ay kahalili ng mga okupado, na nagpapahirap sa paglalaan ng malalaking object. Sa mga mobile scenario, ito ay kritikal dahil ang heap ay karaniwang maliit (64–512 MB sa Android).
Copying Collection ay hinahati ang heap sa dalawang semi-space. Ang mga aktibong object ay kinokopya mula sa isang semi-space patungo sa isa pa nang compact, walang patlang. Pagkatapos ng pagkopya, ang lumang semi-space ay idedeklarang ganap na libre. Ang algorithm ay ganap na nag-aalis ng fragmentation, ngunit nangangailangan ng dobleng dami ng memorya.
Sa mga mobile na kapaligiran, ang Copying Collection ay ginagamit ng mga generational collector para sa mabilis na paglilinis ng mga batang object, na estadistikal na maagang namamatay (hypothesis ng mahinang henerasyon).
Generational Collection ay hinahati ang heap sa mga henerasyon: Young Generation (mga batang object) at Old Generation (mga lumang object na nakaligtas sa ilang paglilinis). Ang paglilinis ng batang henerasyon (Minor GC) ay ginagawa nang madalas at mabilis, dahil karamihan ng mga object ay namamatay nang bata. Ang paglilinis ng lumang henerasyon (Major GC o Full GC) ay bihirang mangyari, ngunit mas tumatagal.
// Demonstrasyon ng generational GC: ang mga batang object ay mabilis namamatay
void processItems(List<Item> items) {
List<Result> results = new ArrayList<>(); // nabubuhay sa buong pamamaraan
for (Item item : items) {
Result r = new Result(item.getValue()); // namatay agad
if (r.isValid()) {
process(r); // r nagiging basura
}
}
saveResults(results); // results lumipat sa Old Gen
}
Sa halimbawang ito, ang mga object ng Result ay nilikha sa loob ng loop at agad na nagiging basura — sila ay perpektong kandidato para sa Young GC. Ang object na results ay nabubuhay nang mas matagal at lumilipat sa Old Generation. Ang paghihiwalay ng mga henerasyon ay nagpapahintulot sa Minor GC na linisin ang mga batang object sa millisecond, nang hindi ginagalaw ang lumang heap.
Ang Android ay dumaan sa landas mula Dalvik VM hanggang ART (Android Runtime), at ang implementasyon ng GC ay isa sa mga pangunahing pagkakaiba sa pagitan ng dalawa. Ang pag-unawa sa arkitektura ng GC sa Android ay tumutulong sa pagsulat ng code na nagpapaliit ng mga paghinto sa mga totoong device.
| Katangian | Dalvik (hanggang 4.4) | ART (5.0+) |
|---|---|---|
| Uri ng GC | Mark-and-Sweep na may Concurrent Mark | Generational + Concurrent |
| Tipikal na paghinto | 10–30 ms | 2–4 ms |
| Kompaktipikasyon | Wala (tanging fragmentation ang lumalaki) | Mayroon (sa background, hindi humihinto ang app) |
| AOT compilation | JIT (Just-In-Time) | AOT + JIT (hybrid) |
Dalvik ay gumamit ng kombinasyon ng Mark-and-Sweep na may concurrent phase. Ang Concurrent Mark ay nagpapahintulot sa application na magpatuloy sa paggana habang tinatahak ang graph ng object, ngunit ang Sweep phase ay nangangailangan ng paghinto ng lahat ng thread (Stop-The-World). Sa mga device na may maliit na RAM (512 MB — 1 GB), ang mga paghinto ay umabot sa 30 ms, na nagdulot ng kapansin-pansing pagbagal ng interface. Bukod dito, hindi ni-compact ng Dalvik ang heap, kaya pagkatapos ng mahabang paggamit, lumalaki ang fragmentation at ang paglalaan ng malalaking object (hal. Bitmap) ay maaaring magdulot ng OutOfMemoryError kahit na may sapat na kabuuang libreng memorya.
ART (Android Runtime) ay nagpakilala ng generational collector na may concurrent compaction. Ang heap ay nahahati sa tatlong rehiyon: Young, Mature (analog ng Old Generation) at Large Object Space (para sa mga object na mas malaki sa 12 KB). Ang paglilinis ng Young region ay ginagawa nang parallel nang hindi humihinto ang mga thread sa karamihan ng mga kaso. Sa Android 10+ ay lumitaw ang Concurrent Copying — ang compaction ay ginagawa sa background thread nang walang Stop-The-World.
Salamat sa arkitektura ng ART, ang tipikal na GC pause ay bumaba sa 2–4 ms, at sa mga scenario na may dominasyon ng mga batang object — sa 0.5–1 ms. Ito ay nagpahintulot sa mga Android device na magbigay ng stable na 60 FPS kahit na sa aktibong paggamit ng memorya.
Sa Java ecosystem ay may ilang implementasyon ng GC, bawat isa ay may sariling profile ng performance. Para sa Android development, ang pagpipilian ay limitado sa ART, ngunit ang kaalaman sa Java GC ay kapaki-pakinabang sa pagsulat ng bahagi ng server ng mga mobile application at sa pag-develop gamit ang Kotlin Multiplatform.
Serial GC — single-thread collector na may kumpletong paghinto ng application (Stop-The-World). Bawat operasyon ng Mark, Sweep at Compact ay ginagawa ng isang thread. Mababa ang performance — hindi ginagamit para sa mga mobile server. Angkop lamang para sa maliliit na application na may heap hanggang 100 MB.
Parallel GC (kilala rin bilang Throughput Collector) ay gumagamit ng maramihang thread para sa lahat ng phase ng paglilinis. Nakatuon sa maximum throughput — pinapaliit ang oras na ginugugol sa GC kaugnay sa oras ng paggana ng application. Aktibo sa pamamagitan ng flag na -XX:+UseParallelGC sa JVM.
G1 (Garbage-First) GC — default collector sa Java 9+. Ang heap ay nahahati sa mga rehiyon na 1–32 MB. Hinuhulaan ng G1 ang oras ng paghinto at sinusubukang manatili sa loob ng itinakdang limitasyon (default 200 ms). Priyoridad: unang nililinis ang mga rehiyon na may pinakamalaking dami ng basura (kaya ang pangalan). Ang G1 ay epektibo para sa mga server na may malaking heap (4–64 GB) at nahuhulaang mga paghinto.
// Pag-activate ng G1 GC na may target na paghinto na 100 ms
// java -XX:+UseG1GC -XX:MaxGCPauseMillis=100 -jar app.jar
public class MemoryMonitor {
private static final long THRESHOLD = 512 * 1024 * 1024; // 512 MB
public void checkHeapUsage() {
Runtime rt = Runtime.getRuntime();
long used = rt.totalMemory() - rt.freeMemory();
if (used > THRESHOLD) {
System.out.println("Lumampas sa threshold ng paggamit ng heap: " + used);
System.out.println("Isaalang-alang ang pagbawas ng mga alokasyon");
}
}
}
Ang pag-monitor ng heap sa pamamagitan ng Runtime ay nagpapahintulot ng maagang pagtuklas ng mga tagas ng memorya. Kung ang used ay lumampas sa 80% ng maximum heap sa stable na paggana — ito ay senyales ng posibleng tagas o labis na paggamit ng memorya ng application.
Kahit ang modernong ART GC ay hindi lumulutas ng lahat ng problema — ang hindi tamang paggamit ng memorya ay nananatiling pangunahing dahilan ng jank at ANR (Application Not Responding). Tingnan natin ang mga pangunahing scenario at pamamaraan ng pag-optimize.
GC Pauses — mga paghinto ng thread ng application habang naglilinis. Sa screen, ito ay lumalabas bilang mga nalaktaw na frame, kapag ang oras sa pagitan ng dalawang frame ay lumampas sa 16.6 ms (60 FPS). Kung ang GC ay tumagal ng 30 ms, isang frame lang ang iginuhit sa halip na dalawa — nakikita ng user ang pagbagal ng interface.
Mga pangunahing dahilan ng mahabang paghinto: malaking bilang ng mga buhay na object sa Old Generation, fragmentation ng heap, madalas na Full GC. Para sa diagnostics, gamitin ang Android Studio Profiler at systrace.
Pangunahing patakaran ng GC-friendly code — bawasan ang bilang ng mga inilaang object. Bawat bagong object ay hindi lang nangangailangan ng paglalaan ng memorya, kundi pati na rin ng kasunod na paglilinis. Kahit na mabilis ang GC, 1000 dagdag na alokasyon bawat segundo ay nagbibigay ng 1000 pagsusuri para sa tagapaglinis.
Ang tagas ng memorya ay nangyayari kapag ang isang object ay nananatiling naaabot, kahit na hindi na ito kailangan. Hindi matatanggal ng GC ang naturang object, at ang memorya ay unti-unting nauubos. Mga karaniwang dahilan: hindi na-unregister na mga listener, static na reference sa Activity, mga anonymous class na kumukuha ng external context, at hindi saradong Cursor/InputStream.
// Tagas ng memorya: anonymous class na humahawak ng reference sa Activity
public void startTask() {
new Thread(new Runnable() { // implicit na humahawak ng this (Activity)
@Override
public void run() {
// mahabang operasyon...
System.out.println("Tapos");
}
}).start();
}
// Pag-aayos: static nested class + WeakReference
private static class TaskRunnable implements Runnable {
private WeakReference<Activity> activityRef;
TaskRunnable(Activity activity) {
this.activityRef = new WeakReference<>(activity);
}
@Override
public void run() {
Activity act = activityRef.get();
if (act != null) {
// ligtas na pagtatrabaho sa Activity
}
}
}
Sa halimbawang ito, ang anonymous Runnable ay kumukuha ng implicit reference sa Activity. Hangga't buhay ang thread — hindi makokolekta ng GC ang Activity, kahit na isinara na ng user ang screen. Ang pag-aayos na WeakReference + static class ay pumuputol sa chain na ito at pinapayagan ang Activity na magamit muli.
Mga Madalas Itanong
Ang GC sa Android (ART) ay isang generational collector na may concurrent compaction, na-optimize para sa mga mobile device na may limitadong memorya. Ang Java GC (G1, ZGC) ay mga server collector na may malalaking heap at nahuhulaang mga paghinto. ART GC ay hindi gumagamit ng JVM flags — lahat ng configuration ay awtomatikong ginagawa sa antas ng OS.
Stop-The-World — ang sandali kung kailan pinipigilan ng collector ang lahat ng thread ng application upang ligtas na tahakin ang graph ng object o magpalaya ng memorya. Kung mas mahaba ang STW, mas kapansin-pansin ang jank. Binawasan ng ART ang tipikal na oras ng STW sa 2–4 ms salamat sa generational architecture.
Gamitin ang Android Studio Memory Profiler — ipinapakita nito ang paglaki ng heap, bilang ng mga alokasyon at nagpapahintulot ng Heap Dump. Para sa malalim na pagsusuri, gamitin ang LeakCanary — awtomatikong natutukoy ng library ang mga tagas at ipinapakita ang chain ng reference na pumipigil sa GC collection.
Full GC — kumpletong paglilinis ng lahat ng henerasyon ng heap, kasama ang Old Generation. Sa mga mobile application, ang Full GC ay maaaring tumagal ng 50–200 ms, na nagdudulot ng kapansin-pansing jank o ANR. Mga pangunahing dahilan: fragmentation ng heap, mga tagas ng memorya, paglampas sa threshold ng Old Generation.
Kotlin ay nagbibigay ng mga coroutine na may structured concurrency — ang pagkansela ng scope ay awtomatikong kumakansela sa lahat ng child coroutine, pumipigil sa mga tagas. Gayundin, sa Kotlin ay may lazy delegate para sa lazy initialization at mga scope operator na nagpapababa ng bilang ng mga pansamantalang object.
Buod
Gagawa kami ng mobile application na turnkey
Gumagawa ang IT Sectr ng mga iOS at Android application para sa mga startup at negosyo mula noong 2017. Magpapayo kami sa iyo at magmumungkahi ng pinakamahusay na solusyon.