Java adalah jenis bahasa koleksi sampah. Keuntungannya adalah bahwa pengembang tidak perlu dengan sengaja mengelola alokasi memori, yang mengurangi kemungkinan bahwa aplikasi akan macet karena kesalahan segmentasi lokal, dan mencegah memori yang tidak masuk akal karena memeras tumpukan (tumpukan). Karena itu, kode yang ditulis lebih aman.
Sayangnya, masih ada banyak kebocoran logis di Java yang rentan terhadap kebocoran memori. Jika Anda tidak hati-hati, aplikasi Android Anda dapat dengan mudah menyia-nyiakan memori yang tidak bebas, yang pada akhirnya akan menyebabkan lemparan kesalahan memori yang habis (out-of-memory, OOM).
1. Alasan kebocoran memori umum adalah bahwa ketika semua referensi ke objek telah dirilis, objek belum dirilis. (Catatan Penerjemah: Kursor lupa tutup, dll.)
2. Alasan untuk kebocoran memori logis adalah bahwa ketika aplikasi tidak lagi membutuhkan objek ini, semua referensi ke objek belum dirilis.
Jika Anda memegang referensi yang kuat ke suatu objek, pengumpul sampah tidak dapat mendaur ulang objek dalam memori.
Dalam pengembangan Android, masalah kebocoran memori yang paling mungkin adalah konteks. Misalnya, konteks aktivitas berisi sejumlah besar referensi memori, seperti hierarki tampilan dan sumber daya lainnya. Setelah konteks bocor, itu juga berarti membocorkan semua objek yang ditunjukkannya. Mesin Android memiliki memori yang terbatas, dan terlalu banyak kebocoran memori dapat dengan mudah menyebabkan OOM.
Mendeteksi kebocoran memori logis membutuhkan penilaian subyektif, terutama siklus hidup objek tidak jelas. Untungnya, aktivitas memiliki siklus hidup yang jelas dan mudah untuk menemukan penyebab kebocoran. Aktivitas.ondestroy () dianggap sebagai akhir dari kehidupan kegiatan. Secara terprogram, harus dihancurkan, atau sistem Android perlu mendaur ulang memori ini (catatan penerjemah: Ketika memori tidak cukup, Android akan mendaur ulang aktivitas yang tidak terlihat).
Jika metode ini dieksekusi, masih ada referensi yang kuat untuk aktivitas di tumpukan, dan pengumpul sampah tidak dapat menandainya sebagai memori daur ulang, dan tujuan awal kami adalah mendaur ulangnya!
Hasilnya adalah bahwa aktivitas bertahan di luar siklus hidupnya.
Aktivitas adalah objek kelas berat dan harus ditangani oleh sistem Android. Namun, kebocoran memori logis selalu terjadi secara tidak sengaja. (Catatan penerjemah: Saya pernah mencoba aktivitas yang menyebabkan kebocoran memori 20m). Di Android, hanya ada dua perangkap yang menyebabkan kebocoran memori potensial:
Variabel statis dari proses global (proses-global). Monster ini yang mengabaikan keadaan aplikasi dan memegang referensi yang kuat untuk aktivitas tersebut.
Thread yang hidup di luar siklus hidup aktivitas. Tidak ada referensi kuat untuk aktivitas yang dibersihkan.
Periksa apakah Anda telah menemukan situasi berikut.
1. Kegiatan statis
Variabel aktivitas statis didefinisikan di kelas, dan instance aktivitas yang sedang berjalan ditetapkan untuk variabel statis ini.
Jika variabel statis ini tidak dibersihkan setelah akhir siklus hidup aktivitas, itu akan menyebabkan kebocoran memori. Karena variabel statis berjalan melalui siklus hidup aplikasi ini, kegiatan yang bocor akan selalu ada dalam proses aplikasi dan tidak akan dikumpulkan oleh pengumpul sampah.
aktivitas aktivitas statis; void setstaticactivity () {Activity = this;} view SABUTTON = findViewById (r.id.sa_button); SABUTTON.SetOnClickListener (view.onclickListener baru (); @Override public onClick (view v) {setstatictivity (); nextAccActicn ();} nextactivity (); nextAccactive ();}};2. Tampilan statis
Situasi serupa dapat terjadi dalam mode singleton, dan jika aktivitas tersebut sering digunakan, itu praktis untuk menyimpan instance dalam memori. Seperti yang disebutkan sebelumnya, memaksa siklus hidup suatu kegiatan cukup berbahaya dan tidak perlu, dan itu tidak dapat dilakukan.
Kasus Khusus: Jika inisialisasi pandangan mengkonsumsi banyak sumber daya dan tetap tidak berubah selama siklus hidup aktivitas, itu dapat diubah menjadi statis dan dimuat ke tampilan hierachy. Dengan cara ini, ketika aktivitas dihancurkan, sumber daya harus dirilis. (Catatan Penerjemah: Memori tidak dirilis dalam kode sampel. Cukup nol tampilan statis ini, tetapi masih belum disarankan untuk menggunakan metode tampilan statis)
tampilan statis; void setStaticView() { view = findViewById(R.id.sv_button);}View svButton = findViewById(R.id.sv_button);svButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { setStaticView(); nextActivity(); }});3. Kelas Instan
Lanjutkan, dengan asumsi ada kelas internal dalam aktivitas, melakukan hal itu dapat meningkatkan keterbacaan dan enkapsulasi. Jika kami membuat kelas internal dan memegang referensi ke variabel statis, selamat, kebocoran memori tidak jauh dari Anda (catatan penerjemah: kosong saat dihancurkan, um).
objek statis pribadi batin; void createInnerClass() { class InnerClass { } inner = new InnerClass();}View icButton = findViewById(R.id.ic_button);icButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { createInnerClass(); nextActivity(); }});Salah satu keuntungan dari kelas internal adalah mereka dapat mengakses kelas eksternal. Sayangnya, alasan kebocoran memori adalah bahwa kelas internal memiliki referensi yang kuat untuk instance kelas eksternal.
4. Kelas anonim
Demikian pula, kelas anonim juga mempertahankan referensi ke kelas eksternal. Jadi kebocoran memori mudah terjadi ketika Anda mendefinisikan asynctsk anonim dalam aktivitas Anda. Ketika tugas asinkron mengeksekusi tugas yang memakan waktu di latar belakang, aktivitas ini sayangnya dihancurkan (catatan penerjemah: keluar pengguna, daur ulang sistem), contoh aktivitas yang dipegang oleh asynctask tidak akan didaur ulang oleh kolektor sampah sampai tugas asinkron selesai.
void startAsynctask () {asynctask baru <void, void, void> () {@override void doinbackground (void ... params) {while (true); } }.execute();} super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);View aicButton = findViewById(R.id.at_button);aicButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { startAsynctask ();5. Handler
Dengan cara yang sama, tentukan runnable anonim dan jalankan dengan penangan kelas anonim. Kelas dalam yang dapat dijalankan akan memiliki referensi implisit ke kelas eksternal dan diteruskan ke pesan dari antrian pesan penangan. Contoh aktivitas tidak akan dihancurkan sampai pesan pesan diproses, menghasilkan kebocoran memori.
void createHandler () {new handler () {@Override public void handlemessage (pesan pesan) {super.handlemessage (pesan); }} .postdelayed (runnable baru () {@Override public void run () {while (true);}}, long.max_value >> 1);} hbutton = findviewById (r.id.h_button); hbutton.setonClickListener (r.id.h_button); hbutton.setonClicklistener (r.id.h_button); hbutton.setonClickerenerer (r.id.h_button); hbutton.setonclickerener (r.id.h_button); hbutton.setonclickerener (r.id.h_button); hbutton.setonclickerener (r.id.h_button); hbutton.setonClickerener (viewlickeron (r.id. v) {createHandler ();6.Threads
Kami sekali lagi menunjukkan kebocoran memori melalui utas dan timertask.
void spawnthread () {thread baru () {@Override public void run () {while (true); }} .start ();} Lihat tbutton = findViewById (r.id.t_button); tbutton.setOnClickListener (view.onClickListener () {@Override public void onClick (view v) {spawnthread (); nextActivity ();}});7. Timertask
Selama itu adalah contoh dari kelas anonim, terlepas dari apakah itu ada di utas pekerja atau tidak, itu akan memiliki referensi ke aktivitas, menghasilkan kebocoran memori.
void scheduleTimer() { new Timer().schedule(new TimerTask() { @Override public void run() { while(true); } }, Long.MAX_VALUE >> 1);}View ttButton = findViewById(R.id.tt_button);ttButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick (view v) {scheduletimer ();8. Manajer Sensor
Akhirnya, Layanan Sistem dapat diperoleh melalui Context.getSystemservice (nama int). Layanan ini bekerja dalam prosesnya masing -masing, membantu aplikasi menangani tugas latar belakang dan interaksi perangkat keras. Jika Anda perlu menggunakan layanan ini, Anda dapat mendaftarkan pendengar, yang akan menyebabkan layanan memiliki referensi ke konteks. Jika pendengar ini tidak dicatat ketika aktivitas dihancurkan, itu akan menyebabkan kebocoran memori.
void registerListener () {Sensormanager Sensormanager = (Sensormanager) getSystemService (Sensor_Service); Sensor sensor = SensormAnager.getDefaultSensor (sensor.type_all); sensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_FASTEST);}View smButton = findViewById(R.id.sm_button);smButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { registerListener(); nextActivity(); }});Meringkaskan
Setelah melihat begitu banyak contoh yang dapat menyebabkan kebocoran memori, mudah untuk memakan semua memori ponsel Anda, membuat pengumpulan sampah dan pemrosesan lebih sering, dan bahkan dalam kasus terburuk, itu akan mengarah ke OOM. Operasi pengumpulan sampah mahal dan dapat menyebabkan kelambatan yang terlihat. Oleh karena itu, perhatikan rantai referensi yang dipegang saat instantiating, dan sering melakukan pemeriksaan kebocoran memori.