Apakah pengumpulan objek merupakan teknik yang sudah usang?

62

Saya sangat akrab dengan konsep objek pooling dan saya selalu berusaha menggunakannya sebanyak mungkin.

Selain itu saya selalu berpikir bahwa penyatuan objek adalah norma standar seperti yang saya amati bahwa Java itu sendiri serta kerangka kerja lainnya menggunakan penyatuan sebanyak mungkin.

Baru-baru ini saya membaca sesuatu yang sama sekali baru (dan kontra-intuitif?) Bagi saya.

Pooling itu sebenarnya membuat kinerja program lebih buruk terutama dalam aplikasi bersamaan, dan disarankan untuk instantiate newobjek sebagai gantinya, karena dalam JVM yang lebih baru, instantiasi objek sangat cepat.

Saya membaca ini di buku: Java Concurrency in Practice

Sekarang saya mulai berpikir jika saya salah memahami sesuatu di sini sejak bagian pertama buku ini disarankan untuk menggunakan Executorskembali Threaditu daripada membuat contoh baru.

Jadi, apakah pengumpulan objek telah menjadi usang saat ini?

pengguna10326
sumber

Jawaban:

72

Ini ditinggalkan sebagai teknik umum, karena - seperti yang Anda perhatikan - penciptaan dan penghancuran objek berumur pendek per se (yaitu alokasi memori dan GC) sangat murah di JVM modern. Jadi, menggunakan kumpulan objek tulisan tangan untuk objek run-of-the-mill Anda kemungkinan besar lebih lambat, lebih rumit dan lebih rentan kesalahan daripada biasa new. *

Ini masih memiliki kegunaannya, untuk objek khusus yang pembuatannya relatif mahal, seperti koneksi DB / jaringan, utas dll.

* Pernah saya harus meningkatkan kinerja aplikasi Java merangkak. Investigasi mengungkap upaya untuk menggunakan kumpulan objek untuk mengalokasikan jutaan objek ... dan orang pintar yang menulisnya menggunakan kunci global tunggal untuk membuatnya aman. Mengganti kolam dengan polos newmembuat aplikasi 30 kali lebih cepat.

Péter Török
sumber
1
Jadi bagaimana kita bisa memutuskan apakah instantiasi suatu objek terlalu mahal?
user10326
3
Jika objek mengkonsumsi sumber daya sistem operasi (utas, I / O, memori bersama, dll.)
kevin cline
13
@ user10326, dengan pengukuran :-) Jika membuat objek Anda membutuhkan waktu lama, dan / atau terkait dengan beberapa sumber daya non-memori khusus, berpotensi terbatas, Anda dapat mempertimbangkan pengumpulan.
Péter Török
8
@ user10326, IMO di lebih dari 95% kasus, kriteria di atas memudahkan untuk memutuskan terlebih dahulu apakah Anda memerlukan kumpulan objek. (Selain itu, dalam hampir semua kasus yang membutuhkan kumpulan, Anda kemungkinan besar akan menggunakan pustaka / kerangka kerja yang ada, yang mungkin memiliki kumpulan objek sudah diterapkan untuk Anda.) Untuk sisanya, masih mudah untuk menyembunyikan pembuatan objek di mis. sebuah pabrik, yang nantinya dapat diimplementasikan kembali sesuai keinginan Anda.
Péter Török
2
Poin yang sangat penting yang dibuat oleh @Peter Torok: banyak kerangka kerja dan pustaka menerapkan pooling untuk Anda, SELALU pastikan Anda belum menggunakan pustaka yang dikumpulkan sebelum mengimplementasikan milik Anda.
hromanko
36

Jawaban atas pertanyaan konkret: 'Apakah objek menggabungkan teknik yang sudah usang?' aku s:

Tidak. Objek pooling banyak digunakan di tempat-tempat tertentu - pooling thread, pooling koneksi database, dll.

Pembuatan objek umum tidak pernah menjadi proses yang lambat. Pooling itu sendiri menghabiskan sumber daya - memori dan kekuatan pemrosesan. Optimalisasi apa pun adalah kompromi.

Aturannya adalah:

Optimalisasi Prematur Jahat !!!

Tetapi kapan optimasi yang diberikan prematur?

Optimalisasi prematur adalah setiap optimasi yang dilakukan, sebelum Anda menemukan hambatan melalui profil menyeluruh .

Boris Yankov
sumber
2
Memang. OP mengatakan "Saya selalu mencoba menggunakannya sebanyak mungkin" - ini masalahnya, IMO.
nerdytenor
@ Boris, Jadi menurut kalimat kedua Anda, kita tidak boleh menolak koneksi dan utas pool db sampai kita membukanya sebagai hambatan melalui profiling?
Pacerier
1
@Pac. Beberapa hasil profil tidak perlu diukur ulang secara konstan :-)
David Bullock
9

Dalam situasi di mana Anda ingin menghindari pengumpulan sampah sepenuhnya, saya pikir pengumpulan objek adalah satu-satunya alternatif yang layak. Jadi tidak, itu sama sekali bukan teknik usang.

Yer
sumber
1
Dan saya akan menambahkan bahwa itu adalah ide yang baik untuk menghindari GC setiap kali objek berumur panjang cukup bahwa mereka telah pindah ke generasi yang lebih tua.
Zan Lynx
8

Mengukur

Ini sepenuhnya tergantung pada kasus penggunaan Anda, ukuran objek Anda, JVM Anda, opsi JVM Anda, GC apa yang telah Anda aktifkan dan sejumlah faktor lainnya.

Singkatnya: mengukur sebelum dan mengukur sesudahnya. Dengan asumsi Anda menggunakan kerangka kerja penyatuan objek (seperti dari Apache) maka tidak boleh terlalu menyakitkan untuk bertukar di antara implementasi.

Tip pengujian kinerja ekstra - biarkan JVM melakukan pemanasan sedikit lebih dulu, jalankan pengujian pada JVM yang sedang berjalan beberapa kali, ini dapat berperilaku berbeda.

Martijn Verburg
sumber
3
"Biarkan JVM melakukan pemanasan dulu," - Saya ingat ketika satu-satunya hal yang harus "menghangatkan" adalah monitor. Oy, semua yang baru sudah tua lagi.
kylben
Satu-satunya hal yang saya perlukan untuk pemanasan adalah kopi!
Disillusioned
@Marijn, Bagaimana Anda membiarkannya "menghangat"?
Pacerier
Lihat Kerangka JMH untuk penjelasan lengkap ( openjdk.java.net/projects/code-tools/jmh ) tetapi pada dasarnya Anda harus memberi JVM kesempatan untuk JIT kode Anda, jalankan GC sebelum benchmark Anda & seterusnya.
Martijn Verburg
8

Pooling itu sebenarnya membuat kinerja program lebih buruk terutama dalam aplikasi bersamaan, dan disarankan untuk instantiate objek baru, karena di JVM baru, instantiasi objek sangat cepat.

Tergantung pada konteksnya.


sumber
1
Jawaban yang sangat bagus, dan meyakinkan. Saya akan menambahkan (mungkin, sebagai tanda bintang?) Bahwa klaim "24 byte" mengacu pada 4 contoh float 4-byte (16 byte), ditambah 4 byte untuk referensi objek, ditambah 4 byte untuk referensi kunci. Ini adalah overhead tepat yang dihilangkan oleh desain Anda.
strickli
5

Saya tidak tahu apakah ada tren yang berubah di sini tetapi pasti akan menjadi kasus yang tergantung . Jika kelas Java Anda mengelola sumber daya eksternal, seperti koneksi RMI atau memuat file sumber daya dll - maka tentu saja biaya untuk instance objek masih bisa tinggi (meskipun sumber daya tersebut mungkin sudah dikumpulkan untuk Anda!). Sebagai praktik umum, saya setuju dengan buku itu.

Jeremy
sumber
Nah sekarang saya tidak tahu. Karena bahkan dalam hal ini Anda menggambarkan yang (sebelum membaca ini) saya akan menggunakan pooling, saya juga akan memiliki overhead.1) Konstruksi baru untuk menangani pooling 2) Sinkronisasi untuk mendapatkan / melepaskan objek dari kolam 3) memelihara kolam dll. Jadi saya sekarang berpikir bahwa mungkin tidak ada kasus penggunaan yang berguna kecuali misalnya caching soket daripada membuka yang baru setiap kali terhubung ke server. Dan kasus ini karena jaringan latensi dan bukan overhead pembuatan instantiation
user10326
@ user10326 Ya persis. Saya melihat membuka soket sebagai bagian dari overhead instantiation, jika tugas kelas untuk melakukan itu dan harus diinisialisasi dalam konstruktor maka dampak latensi & IO adalah apa yang Anda khawatirkan.
Jeremy