2.40. Memori dan garbage collection¶
MicroPython mengelola memori dengan cara yang sama seperti CPython: setiap objek hidup di heap, dan sebuah garbage collector (GC) membebaskan objek yang tidak lagi direferensikan oleh apa pun. Pada perangkat dengan beberapa ratus kilobyte RAM, sesekali perlu memperhatikan cara heap digunakan; di Python desktop, hal ini jarang terjadi.
2.40.1. Heap¶
Heap adalah wilayah RAM -- pada sebagian besar kamera OpenMV sebenarnya terbagi di lebih dari satu pool memori fisik -- yang dikeluarkan oleh runtime ke objek Python. Setiap kali ekspresi Python membuat objek baru (sebuah list, string, dict, tuple, apapun yang bukan integer kecil atau singleton), sebuah blok byte keluar dari heap untuk menampungnya. Ketika GC mendeteksi bahwa sebuah objek tidak dapat dijangkau, blok tersebut dikembalikan ke pool bebas asalnya.
Dua fungsi dalam modul gc layak diketahui:
gc.mem_free()-- perkiraan jumlah byte bebas di heap saat ini.gc.collect()-- jalankan siklus pengumpulan segera daripada menunggu runtime memicunya.
import gc
print("before:", gc.mem_free())
big = [0] * 10000
print("after :", gc.mem_free())
del big
gc.collect()
print("freed :", gc.mem_free())
Angka-angka persis bergantung pada build; arah perubahannya adalah yang penting: mengalokasikan hal-hal besar menurunkan mem_free, dan melepas referensi ditambah sebuah gc.collect mengembalikan heap.
2.40.2. Fragmentasi¶
Pool bebas tidak secara ajaib kontinu. Saat objek datang dan pergi dengan masa hidup yang berbeda, ruang bebas terpecah menjadi potongan-potongan yang semakin kecil meskipun ukuran totalnya masih besar. Mengalokasikan objek yang lebih besar dari potongan bebas tunggal terbesar gagal dengan MemoryError -- meskipun secara teknis ada cukup total RAM bebas.
Total RAM bebas yang sama dapat menampung buffer besar (kiri) atau menolaknya (kanan) tergantung seberapa terfragmentasinya.¶
Fragmentasi sebagian besar menjadi kekhawatiran pada skrip yang berjalan lama yang terus mengalokasikan dan membebaskan buffer dengan ukuran berbeda. Mitigasi paling efektif adalah pra-alokasi buffer berumur panjang di dekat awal program, sebelum banyak alokasi berumur pendek sempat menyebarkannya.
2.40.3. Pra-alokasi¶
Dua pola membuat heap berperilaku baik:
Alokasikan buffer berukuran tetap sekali dan gunakan kembali, daripada membangun list atau
bytearraybaru per iterasi.Pindahkan konstanta dan tabel pencarian keluar dari loop dalam sehingga dibuat sekali.
buf = bytearray(64) # one allocation, reused below
def fill(value):
for i in range(len(buf)):
buf[i] = value
fill(0)
fill(255)
Bandingkan dengan versi yang membuat bytearray baru di dalam loop: setiap iterasi menghasilkan sampah yang harus dibersihkan GC nanti. Versi pra-alokasi tidak menghasilkan sampah sama sekali.
2.40.4. Kapan memanggil gc.collect¶
gc.collect() biasanya otomatis -- runtime memicunya ketika alokasi tidak dapat menemukan cukup memori bebas. Memanggilnya secara manual berguna dalam dua situasi:
Tepat setelah sejumlah besar objek keluar dari cakupan, untuk membebaskannya segera daripada menunggu alokasi berikutnya membayar biayanya.
Tepat sebelum bagian yang membutuhkan jumlah memori bebas maksimum yang diketahui, untuk menghindari GC menyala di tengah operasi yang sensitif terhadap waktu.
Menyebarkan panggilan gc.collect di mana-mana tidak membuat program lebih cepat -- pengumpulan itu sendiri membutuhkan waktu. Gunakan dengan bijak, pada titik-titik di mana biaya pengumpulan yang tidak terjadwal lebih buruk dari biaya yang Anda jalankan dengan sengaja.