Pengumpul sampah di Android

108

Saya telah melihat banyak jawaban Android yang menyarankan memanggil pengumpul sampah dalam beberapa situasi.

Apakah praktik yang baik untuk meminta pengumpul sampah di Android sebelum melakukan operasi yang membutuhkan banyak memori? Jika tidak, haruskah saya memanggilnya hanya jika saya mendapatkan OutOfMemorykesalahan?

Apakah ada hal lain yang harus saya gunakan sebelum beralih ke pemulung?

hpique
sumber

Jawaban:

144

Untuk versi sebelum 3.0 honeycomb : Ya, lakukan panggilan System.gc() .

Saya mencoba membuat Bitmap, tetapi selalu mendapatkan "VM kehabisan memori error". Tapi, ketika saya menelepon System.gc()dulu, tidak apa-apa.

Saat membuat bitmap, Android sering gagal karena kesalahan kehabisan memori, dan tidak mencoba mengumpulkan sampah terlebih dahulu . Karenanya, panggil System.gc(), dan Anda memiliki cukup memori untuk membuat Bitmap.

Jika membuat Objek, menurut saya System.gcakan dipanggil secara otomatis jika diperlukan, tetapi tidak untuk membuat bitmap. Itu gagal begitu saja.

Jadi saya sarankan menelepon secara manual System.gc()sebelum membuat bitmap.

steve
sumber
39
Ini karena sebelum honeycomb, data bitmap tidak disimpan di VM sehingga tidak akan memicu GC. Ini seharusnya tidak menjadi masalah di Honeycomb dan yang lebih baru.
Timmmm
2
@Timmmm tetapi sebenarnya itu masalah saya, saya hanya menetapkan harga yang besar menjadi true.
Lei Leyba
118

Secara umum, di hadapan seorang kolektor sampah, itu adalah tidak pernah praktik yang baik untuk memanggil secara manual GC. GC diatur berdasarkan algoritme heuristik yang bekerja paling baik saat diserahkan ke perangkatnya sendiri. Memanggil GC secara manual sering kali menurunkan kinerja.

Kadang-kadang , dalam beberapa situasi yang relatif jarang, seseorang mungkin menemukan bahwa GC tertentu salah, dan panggilan manual ke GC kemudian dapat meningkatkan banyak hal, dari segi kinerja. Ini karena sangat tidak mungkin untuk menerapkan GC "sempurna" yang akan mengelola memori secara optimal di semua kasus. Situasi seperti itu sulit untuk diprediksi dan bergantung pada banyak detail implementasi yang tidak kentara. "Praktik yang baik" adalah membiarkan GC berjalan dengan sendirinya; panggilan manual ke GC adalah pengecualian, yang harus dibayangkan hanya setelah masalah kinerja yang sebenarnya telah disaksikan.

Thomas Pornin
sumber
8
1 untuk jawaban independen platform yang bagus. Menunggu untuk melihat apakah seseorang muncul dengan jawaban khusus Android sebelum memilih.
hpique
8
Saya setuju dengan apa yang Anda tulis jika Anda mengizinkan "kinerja" berarti sesuatu yang lebih umum daripada efisiensi CPU. Di perangkat Android, persepsi pengguna tentang kinerja adalah yang terpenting. Pengembang mungkin lebih suka menjalankan GC saat pengguna menekan tombol misalnya, sehingga pengguna tidak akan mengetahui GC.
Presiden James K. Polk
5
Seringkali penting dalam game bahwa GC tidak berjalan saat game berjalan (ini mengharuskan semua objek dibuat sebelumnya dan didaur ulang atau serupa), tetapi saat game dijeda, inilah saat yang tepat untuk GC.
Tepuk
4
Sebelum honeycomb, data bitmap tidak disimpan dalam memori VM. Sistem tidak akan mendeteksi jika Anda telah menggunakan terlalu banyak memori non-VM karena bitmap dan menjalankan GC (yang akan menjalankan Bitmap.finalize()metode yang membebaskan memori non-VM). Oleh karena itu dalam kasus ini, Anda harus membahas kepala GC dan menjalankan Bitmap.recycle()atau System.gc()jika perlu. Tapi hanya sebelum sarang lebah.
Timmmm
1
@ThomasPornin - Di sisi lain, sebagai pemrogram aplikasi, Anda tahu sesuatu yang tidak diketahui oleh OS: saat aplikasi Anda sekarang akan membuat perubahan besar dalam cara menggunakan memori, dan itu tidak akan terlalu mengganggu pengalaman pengguna untuk mengambil jeda sekarang, daripada pada waktu yang sewenang-wenang di masa mendatang . Artinya, mungkin masuk akal untuk membuat panggilan yang jarang , pada transisi besar dalam cara aplikasi digunakan. Ini jarang terjadi dalam artian bahwa seseorang tidak boleh sering memanggil GC, tetapi umum terjadi karena hampir semua aplikasi penting memiliki momen yang diketahui oleh desain.
ToolmakerSteve
26

Kehabisan memori di aplikasi android sangat umum jika kita tidak menangani bitmap dengan benar, Solusi untuk masalah tersebut adalah

if(imageBitmap != null) {
    imageBitmap.recycle();
    imageBitmap = null;
}
System.gc();
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 3;
imageBitmap = BitmapFactory.decodeFile(URI, options);
Bitmap  scaledBitmap = Bitmap.createScaledBitmap(imageBitmap, 200, 200, true);
imageView.setImageBitmap(scaledBitmap);

Dalam kode di atas Saya baru saja mencoba mendaur ulang bitmap yang akan memungkinkan Anda untuk mengosongkan ruang memori yang digunakan, jadi kehabisan memori mungkin tidak terjadi. Saya telah mencobanya berhasil untuk saya.

Jika masih menghadapi masalah Anda juga bisa menambahkan garis ini juga

BitmapFactory.Options options = new BitmapFactory.Options();
options.inTempStorage = new byte[16*1024];
options.inPurgeable = true;

untuk informasi lebih lanjut lihat tautan ini

https://web.archive.org/web/20140514092802/http://voices.yahoo.com/android-virtual-machine-vm-out-memory-error-7342266.html?cat=59


CATATAN: Karena "jeda" sesaat yang disebabkan oleh gc, tidak disarankan untuk melakukan ini sebelum setiap alokasi bitmap.

Desain yang optimal adalah:

  1. Bebaskan semua bitmap yang tidak lagi diperlukan , dengan if / recycle / nullkode yang ditampilkan. (Buat metode untuk membantu itu.)

  2. System.gc();

  3. Alokasikan bitmap baru.

yogesh
sumber
19

Jika Anda mendapatkan OutOfMemoryError maka biasanya sudah terlambat untuk memanggil pengumpul sampah ...

Berikut kutipan dari Pengembang Android:

Seringkali, pengumpulan sampah terjadi karena berton-ton benda kecil berumur pendek dan beberapa pengumpul sampah, seperti pengumpul sampah generasi, dapat mengoptimalkan pengumpulan benda-benda ini sehingga aplikasi tidak terlalu sering terganggu. Sayangnya, pengumpul sampah Android tidak dapat melakukan pengoptimalan seperti itu dan pembuatan objek berumur pendek di jalur kode kinerja kritis sangat mahal untuk aplikasi Anda.

Jadi menurut pemahaman saya, tidak ada kebutuhan mendesak untuk menelepon gc. Lebih baik menghabiskan lebih banyak usaha untuk menghindari pembuatan objek yang tidak perlu (seperti pembuatan objek di dalam loop)

Andreas Dolk
sumber
6
Tidak bisakah kutipan diartikan dengan cara lain? Mungkin GC perlu dipanggil secara manual untuk mengumpulkan objek tersebut sebelum menghabiskan terlalu banyak memori.
hpique
@ Hgpc: Saya tidak melihat bagaimana kutipan dapat diartikan seperti yang Anda sarankan. Saya menduga dokumentasinya adalah pengakuan, mengakui bahwa GC mereka sederhana; saat memori hampir habis, GC penuh dijalankan.
Presiden James K. Polk
Memanfaatkan sepenuhnya objek kompleks, dan kerangka kerja menggunakan objek kompleks, cenderung menggunakan waktu pengembangan dengan lebih baik daripada pengoptimalan prematur. Khawatir tentang pengoptimalan adalah jebakan yang lebih mudah dilakukan untuk Android daripada Enterprise Java karena kami secara tidak sadar terus memikirkan kinerja saat membuat kode aplikasi seluler. Terutama sebagai pengembang kerangka kerja, yang harus memikirkan kinerja, membocorkan sudut pandang itu ke dalam dokumentasi resmi mereka ketika mereka tidak berhati-hati.
LateralFractal
9

Sepertinya System.gc()tidak berfungsi pada Art Android 6.0.1 Nexus 5x, Jadi saya gunakan Runtime.getRuntime().gc();sebagai gantinya.

cmicat
sumber
1
System.gc()adalah fungsi pembungkus untuk Runtime.getRuntime().gc(). Lihat android.googlesource.com/platform/libcore/+/…
Nathan F.
Ya, dari sumber dan dokumentasinya sepertinya sama, tapi memang System.gc()tidak berhasil untuk saya tapi Runtime.getRuntime().gc()bisa!
Ivan
7

Aplikasi saya mengelola banyak gambar dan mati dengan OutOfMemoryError. Ini membantu saya. Dalam Manifest.xml Add

<application
....
   android:largeHeap="true"> 
Klykoo
sumber
9
Google tidak menyukai ini
Pedro Paulo Amorim
1
@PedroPauloAmorim jelaskan kenapa?
Machado
2
Jangan gunakan largeHeap kecuali Anda yakin dengan apa yang Anda lakukan. Menggunakan tumpukan besar membuat Pengumpul sampah bekerja lebih keras karena harus melakukan perulangan melalui banyak data sampah sebelum membersihkan memori.
Prakash
7

Secara umum, Anda tidak boleh memanggil GC secara eksplisit dengan System.gc (). Bahkan ada kuliah IO ( http://www.youtube.com/watch?v=_CruQY55HOk ) di mana mereka menjelaskan apa arti log jeda GC dan di mana mereka juga menyatakan untuk tidak pernah memanggil System.gc () karena Dalvik lebih tahu dari pada Anda saat melakukannya.

Di sisi lain seperti yang disebutkan dalam jawaban di atas, proses GC di Android (seperti yang lainnya) terkadang buggy. Ini berarti algoritme Dalvik GC tidak setara dengan Hotspot atau JVM JRockit dan mungkin mengalami kesalahan pada beberapa kesempatan. Salah satunya adalah saat mengalokasikan objek bitmap. Ini rumit karena menggunakan memori Heap dan Non Heap dan karena satu contoh objek bitmap yang longgar pada perangkat yang dibatasi memori sudah cukup untuk memberi Anda pengecualian OutOfMemory. Jadi memanggilnya setelah Anda tidak memerlukan bitmap ini lagi biasanya disarankan oleh banyak pengembang dan bahkan dianggap praktik yang baik oleh sebagian orang.

Praktik yang lebih baik adalah menggunakan .recycle () pada bitmap karena untuk itulah metode ini dibuat, karena menandai memori asli bitmap sebagai aman untuk dihapus. Perlu diingat bahwa ini sangat bergantung pada versi, yang berarti ini umumnya akan diperlukan pada versi Android yang lebih lama (menurut saya Pre 3.0) tetapi tidak akan diperlukan pada versi yang lebih baru. Juga tidak ada salahnya menggunakannya pada versi eter yang lebih baru (jangan lakukan ini dalam satu lingkaran atau sesuatu seperti itu). Runtime ART baru banyak berubah di sini karena mereka memperkenalkan "partisi" Heap khusus untuk objek besar, tetapi menurut saya tidak ada salahnya melakukan hal ini dengan ART eter.

Juga satu catatan yang sangat penting tentang System.gc (). Metode ini bukan perintah yang harus ditanggapi oleh Dalvik (atau JVM). Anggap saja lebih seperti mengatakan ke mesin Virtual "Bisakah Anda melakukan pengumpulan sampah jika tidak merepotkan".

Igor Čordaš
sumber
3

Saya akan mengatakan tidak, karena dokumen Pengembang tentang status penggunaan RAM :

...
GC_EXPLICIT

GC eksplisit, seperti saat Anda memanggil gc () (yang harus Anda hindari memanggil dan sebagai gantinya mempercayai GC untuk berjalan saat diperlukan).

...

Saya telah menandai bagian yang relevan dengan huruf tebal.

Lihatlah seri YouTube, Pola Kinerja Android - ini akan menunjukkan kepada Anda tip-tip dalam mengelola penggunaan memori aplikasi Anda (seperti menggunakan Android ArrayMapdan SparseArraybukannya HashMaps).

Farbod Salamat-Zadeh
sumber
3

Catatan singkat untuk pengembang Xamarin .

Jika Anda ingin menelepon System.gc()di aplikasi Xamarin.Android Anda harus meneleponJava.Lang.JavaSystem.Gc()

Denis Gordin
sumber
2

Tidak perlu memanggil pengumpul sampah setelah OutOfMemoryError.

Javadoc dengan jelas menyatakan:

Thrown when the Java Virtual Machine cannot allocate an object because it is out of memory, and no more memory could be made available by the garbage collector.

Jadi, pengumpul sampah sudah mencoba mengosongkan memori sebelum menghasilkan kesalahan tetapi tidak berhasil.

perdian
sumber
8
Android Javadoc tidak menyatakan itu, dan kemungkinan besar implementasinya berbeda. d.android.com/reference/java/lang/OutOfMemoryError.html
hpique
Anda benar bahwa ini tidak berlaku di Android. Tetapi sekali lagi Anda tidak dapat menangani OOE pada runtime eter sehingga Anda tidak dapat berbuat banyak tentang hal itu bahkan jika ini / tidak benar.
Igor Čordaš