Memory leak — isa sa mga pinakamapanlinlang na problema sa mobile development. Ang memorya ng app ay patuloy na lumalaki hanggang sa maabot ang limitasyon na itinakda ng OS, pagkatapos ay magkakaroon ng OutOfMemoryError o sapilitang pagtatapos. Ayon sa Square Engineering, halos 40% ng mga Android app ay may kahit isang memory leak na makikita lamang sa profiling. Talakayin natin ang mga sanhi at paraan ng pagpigil sa paglaki ng memorya.
Mga pangunahing punto
Memory leak — sitwasyon kung saan ang isang object na hindi na kailangan ng app ay nananatili sa heap dahil may aktibong reference mula sa root set (GC Root). Itinuturing ng garbage collector na buhay ang naturang object at hindi ito tinatanggal.
Pamamaga ng memorya (memory bloat) — mas malawak na problema kapag ang app ay kumokonsumo ng mas maraming memorya kaysa kinakailangan para sa kasalukuyang mga gawain. Mga sanhi: labis na caching, pagdoble ng mga object, hindi optimal na mga istruktura ng data, at fragmentation ng heap.
Sa Android bawat app ay inilalaan ng limitadong heap (karaniwang 64-512 MB depende sa device at bersyon ng OS). Sa iOS ang limitasyon ay hindi gaanong mahigpit, ngunit ang system ay nagpapadala ng babala sa memorya kapag papalapit sa limitasyon.
| Katangian | Android | iOS |
|---|---|---|
| Limitasyon ng heap | 64-512 MB (depende sa device) | Implicit (system) |
| Garbage collection | ART (Concurrent, Compact) | ARC (Automatic Reference Counting) |
| Mekanismo ng leak | GC Root references | Retain cycles (malakas na reference cycles) |
| Resulta | OutOfMemoryError | Babala sa memorya → pagtatapos |
Ayon sa Facebook Engineering Blog, ang memory leak ay sanhi ng ~15% ng mga crash report sa mobile app. Sa Android, idinagdag ang ANR dahil sa madalas na GC pause kapag kulang sa memorya.
Static na reference sa Activity — klasiko ng Android leaks. Kung ang isang static na field o singleton ay nag-iimbak ng reference sa Activity, hindi ito kokolektahin ng GC kahit pagkatapos ng finish(), habang buhay ang singleton. Ang Activity ay isang mabigat na object na naglalaman ng View hierarchy, resources, at Context.
object LeakHolder {
var activityRef: Activity ?= null // leak: static na reference sa Activity
}
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle ?= null) {
super.onCreate(savedInstanceState)
LeakHolder.activityRef = this // ❌ Ang MainActivity ay hindi kailanman makokolekta ng GC
}
}
Mga anonymous na klase at lambda — implicitly na nag-iimbak ng reference sa panlabas na klase. Kung ang Runnable o Callback ay ipinasa sa panlabas na serbisyo at ang Activity ay nawasak, ang anonymous class object ay nakabitin pa rin sa queue at hindi pinapayagan ang Activity na ma-garbage collect.
Sa iOS ang pangunahing problema ay retain cycles: dalawang object ang nag-iimbak ng malalakas na reference sa isa't isa at hindi mababawasan ng ARC ang reference count para sa alinman. Karaniwang kaso: isang closure na malakas na kumukuha ng self, at self na may hawak na reference sa closure.
LeakCanary — library mula sa Square para sa awtomatikong pagtuklas ng leak sa Android. Pagkatapos ng pagkasira ng Activity o Fragment, sinusuri nito kung ang object ay nakolekta ng GC. Kung hindi — gumagawa ito ng heap dump at nagpapakita ng leak trace.
// LeakCanary 2.x — auto-integration sa pamamagitan ng Application
class ExampleApplication : Application() {
override fun onCreate() {
super.onCreate()
// Awtomatikong nag-i-install ang LeakCanary sa debug build
// sa pamamagitan ng ContentProvider — zero code setup
}
}
// Sapilitang tawag sa pagsusuri
AppWatcher.objectWatcher.watch(watchedObject, "leak description")
Android Studio Profiler — built-in na tool para sa real-time na pagsubaybay sa memorya. Nagbibigay-daan sa pag-record ng heap dump, paghahanap ng mga kahina-hinalang object (Retained Size > 1 MB), at pagsubaybay sa GC root path papunta sa bawat object.
Para sa iOS gamitin ang Xcode Memory Graph Debugger. Binibigyang-diin nito ang graph ng mga object sa memorya, ipinapakita ang retain cycles at pinapayagan ang agarang pagtuklas ng mga circular reference. Available din ang Instruments > Allocations para sa pangmatagalang pagsubaybay.
WeakReference — pangunahing mekanismo para sa mga reference na hindi dapat hadlangan ang garbage collection. Kung magpasya ang GC na tanggalin ang object, ang WeakReference ay nagbabalik ng null. Ginagamit para sa mga callback, listener, at reference sa mga UI component mula sa mga background thread.
Mga Lifecycle-aware na component — arkitektural na diskarte na ipinatupad sa Android Jetpack (Lifecycle, LiveData, Flow, coroutines). Awtomatikong kinakansela ang mga subscription sa onDestroy, na inaalis ang pangunahing klase ng leaks.
class MyViewModel : ViewModel() {
private val _data = MutableLiveData<List<User>>()
val data: LiveData<List<User>> get() = _data
fun loadData() {
viewModelScope.launch {
val result = repository.fetchData()
_data.postValue(result)
// awtomatikong kinakansela ang coroutine sa onCleared()
}
}
}
viewModelScope at lifecycleScope — built-in na CoroutineScope sa Android na kinakansela sa kaukulang lifecycle event. Inaalis nito ang mga leak sa pamamagitan ng coroutine — ang pinakakaraniwang senaryo sa modernong Android development.
Memory Profiler in Android Studio — pangunahing tool para sa pagsubaybay sa heap. Nagpapakita ng live allocations, heap snapshot, bilang ng mga object ayon sa uri. Pinapayagan ang pag-record ng dump at pagsusuri nito sa MAT (Memory Analyzer Tool) para sa paghahanap ng mga kahina-hinalang object.
Eclipse MAT — desktop analyzer ng heap dump. Pagkatapos mag-load ng HPROF file mula sa Android Studio, nagtatayo ang MAT ng dominator tree, ipinapakita ang retain size ng bawat object, at nag-aalok ng awtomatikong pagsusuri ng mga kahina-hinalang leak sa pamamagitan ng Leak Suspects Report.
Xcode Memory Graph — visual debugger para sa retain cycles. Sa pag-click sa Memory Graph Debugger button, itinitigil ng Xcode ang app, nagtatayo ng kumpletong graph ng mga object sa memorya, at itinatampok ang retain cycles sa pula.
| Tool | Platform | Katangian |
|---|---|---|
| LeakCanary | Android | Awtomatikong pagtuklas ng leak pagkatapos ng destroy |
| Memory Profiler | Android Studio | Heap dump + live allocations |
| Eclipse MAT | Android | Dominator tree, Leak Suspects Report |
| Memory Graph | iOS (Xcode) | Visualisador ng retain cycles |
Ayon sa Google I/O 2023, ang mga app na gumagamit ng LeakCanary sa debug build ay nakakabawas ng bilang ng memory-related crash ng 30-50% sa unang 2 buwan pagkatapos ng implementasyon. Inirerekomenda na idagdag ang LeakCanary sa onboarding phase ng proyekto.
Mga madalas itanong
Leak — mga object na hindi naa-access ng code ngunit hindi tinatanggal ng GC dahil sa aktibong reference. Pamamaga — ang app ay nag-iimbak ng mga object na lohikal na kailangan ngunit sa sobrang dami (hal. 50 MB cache sa isang tumatakbong app na 80 MB). Ang pamamaga ay ginagamot sa arkitektura, ang leak — sa pamamagitan ng tamang pamamahala ng reference.
LeakCanary ay gumagamit ng ObjectWatcher — pagkatapos ng onDestroy() Activity, lumilikha ito ng WeakReference sa Activity at pinapatakbo ang GC. Kung pagkatapos ng 5 segundo ang WeakReference ay hindi nalinis, gumagawa ang LeakCanary ng heap dump, sinusuri ang pinakamaikling reference chain mula GC Root hanggang object, at ipinapakita ang eksaktong leak stack na may pangalan ng file at linya ng code.
Bitmap ay gumagamit ng memorya sa labas ng Java heap sa native memory (native heap). Laki ng isang Bitmap = lapad × taas × 4 bytes (ARGB_8888). Ang 12 MP na larawan (4000×3000) ay sumasakop ng 48 MB. Hindi laging maaaring palayain ng Android ang native memory sa tamang oras, na kapag naipon ang maraming Bitmap ay humahantong sa OOM kahit na may sapat na Java heap.
Retain cycle — sitwasyon sa ARC kung saan dalawang object ang nag-iimbak ng malalakas na reference sa isa't isa at ang reference count ay hindi kailanman umaabot sa zero. Karaniwang halimbawa: ViewController na may malakas na reference sa closure, at closure na malakas na kumukuha ng self. Solusyon: gumamit ng [weak self] o [unowned self] sa mga closure.
Ang laki ng heap ay depende sa device at bersyon ng Android. Para sa lumang device (API 15-24) — 64-128 MB. Para sa modernong device (API 25+) — 256-512 MB. Ang eksaktong halaga ay makukuha sa pamamagitan ng ActivityManager.getMemoryClass(). Para sa malalaking app (laro, editor) mayroong largeHeap=true sa manifest, na nagbibigay ng hanggang 1 GB.
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.
Basahin din