Saya diberitahu oleh seorang rekan bahwa dalam pembuatan objek Java adalah operasi paling mahal yang bisa Anda lakukan. Jadi saya hanya bisa menyimpulkan untuk membuat objek sesedikit mungkin.
Ini agaknya mengalahkan tujuan pemrograman berorientasi objek. Jika kita tidak membuat objek maka kita hanya menulis satu gaya C kelas panjang, untuk optimasi?
Jawaban:
Rekan Anda tidak tahu apa yang mereka bicarakan.
Operasi Anda yang paling mahal adalah mendengarkan mereka . Mereka menyia-nyiakan waktu Anda untuk mengarahkan Anda ke informasi yang lebih dari satu dekade kedaluwarsa (sejak tanggal asli jawaban ini diposting) serta Anda harus menghabiskan waktu memposting di sini dan meneliti Internet untuk kebenaran.
Semoga mereka hanya memuntahkan sesuatu yang mereka dengar atau baca dari lebih dari satu dekade yang lalu dan tidak tahu yang lebih baik. Saya akan mengambil apa pun yang mereka katakan sebagai tersangka juga, ini harus menjadi kesalahan yang diketahui oleh siapa pun yang tetap up to date.
Semuanya adalah Obyek (kecuali
primitives
)Segala sesuatu selain primitif (
int, long, double
, dll) adalah Objek di Jawa. Tidak ada cara untuk menghindari pembuatan Objek di Jawa.Penciptaan objek di Jawa karena strategi alokasi memorinya lebih cepat daripada C ++ dalam banyak kasus dan untuk semua tujuan praktis dibandingkan dengan segala hal lain di JVM dapat dianggap "bebas" .
Pada awal tahun 2000-an awal implementasi JVM memang memiliki beberapa overhead kinerja dalam alokasi Obyek yang sebenarnya. Ini tidak terjadi sejak setidaknya 2005.
Jika Anda menyetel
-Xms
untuk mendukung semua memori yang Anda butuhkan agar aplikasi Anda dapat berjalan dengan benar, GC mungkin tidak pernah harus menjalankan dan menyapu sebagian besar sampah dalam implementasi GC modern, program yang berumur pendek mungkin tidak pernah GC sama sekali.Itu tidak mencoba dan memaksimalkan ruang kosong, yang merupakan herring merah, itu memaksimalkan kinerja runtime. Jika itu berarti JVM Heap hampir 100% dialokasikan sepanjang waktu, maka jadilah itu. Memori tumpukan JVM gratis tidak memberi Anda apa-apa hanya duduk di sana saja.
Ada kesalahpahaman bahwa GC akan membebaskan memori kembali ke seluruh sistem dengan cara yang bermanfaat, ini sepenuhnya salah!
Tumpukan JVM tidak tumbuh dan menyusut sehingga sisa sistem secara positif dipengaruhi oleh memori bebas di Tumpukan JVM .
-Xms
mengalokasikan SEMUA dari apa yang ditentukan pada startup dan heuristiknya adalah untuk tidak pernah benar-benar melepaskan memori itu kembali ke OS untuk dibagikan dengan proses OS lainnya sampai instance JVM berhenti sepenuhnya.-Xms=1GB -Xmx=1GB
mengalokasikan 1GB RAM terlepas dari berapa banyak objek yang sebenarnya dibuat pada waktu tertentu. Ada beberapa pengaturan yang memungkinkan persentase memori tumpukan untuk dilepaskan, tetapi untuk semua tujuan praktis JVM tidak pernah mampu melepaskan cukup memori ini agar hal ini dapat terjadijadi tidak ada proses lain yang bisa mendapatkan kembali memori ini, sehingga sisa dari sistem tidak mendapat manfaat dari JVM Heap menjadi gratis juga. RFE untuk ini "diterima" 29-NOV-2006, tetapi belum pernah dilakukan. Ini adalah perilaku yang tidak dianggap masalah oleh siapa pun yang berwenang.Ada kesalahpahaman bahwa membuat banyak objek kecil yang berumur pendek menyebabkan JVM berhenti untuk jangka waktu yang lama, ini sekarang salah juga
Algoritma GC saat ini sebenarnya dioptimalkan untuk membuat banyak banyak objek kecil yang berumur pendek, yang pada dasarnya adalah 99% heuristik untuk objek Java di setiap program. Upaya di Object Pooling benar-benar akan membuat kinerja JVM lebih buruk dalam banyak kasus.
Satu-satunya Objek yang perlu dikumpulkan hari ini adalah Obyek yang merujuk pada sumber daya terbatas yang berada di luar JVM; Soket, File, Koneksi Basis Data, dll dan dapat digunakan kembali. Objek biasa tidak dapat digabungkan dalam arti yang sama seperti dalam bahasa yang memungkinkan Anda akses langsung ke lokasi memori. Objek caching adalah konsep yang berbeda dan mungkin atau mungkin tidak apa yang beberapa orang naif menyebut pooling , dua konsep yang tidak sama dan tidak boleh digabungkan.
Algoritma GC modern tidak memiliki masalah ini karena mereka tidak mengalokasikan pada jadwal, mereka mendelokasi ketika memori bebas diperlukan dalam generasi tertentu. Jika tumpukan cukup besar, maka tidak ada alokasi yang cukup lama untuk menyebabkan jeda.
Berorientasi Objek Bahasa dinamis mengalahkan C bahkan sekarang berhari-hari pada pengujian sensitif komputasi.
sumber
_alloca
, diamortisasi.new
kata kunci di tempat hotspot. Saya telah melihat orang menggunakannew ImageIcon(Image)
dalampaint()
metode objek Swing, yang cukup mahal dan membuat seluruh UI yang super lamban. Jadi itu bukan jawaban hitam dan putih, pikirkan sebelum Anda menggunakannew
suatu tempat.Intinya: Jangan kompromi desain Anda untuk mengambil jalan pintas membuat objek. Hindari membuat objek yang tidak perlu. Jika masuk akal, desain untuk menghindari operasi yang berlebihan (dalam bentuk apa pun).
Bertentangan dengan sebagian besar jawaban - ya, alokasi objek TIDAK memiliki biaya yang terkait. Ini adalah biaya rendah, tetapi Anda harus menghindari membuat objek yang tidak perlu. Sama seperti Anda harus menghindari apa pun yang tidak perlu dalam kode Anda. Grafik objek besar membuat GC lebih lambat, menyiratkan waktu eksekusi yang lebih lama karena Anda mungkin akan memiliki lebih banyak panggilan metode, memicu lebih banyak cache CPU yang meleset, dan meningkatkan kemungkinan proses Anda ditukar ke disk dalam kasus RAM yang rendah.
Sebelum ada yang mengomel tentang ini menjadi kasus tepi - Saya telah membuat profil aplikasi yang, sebelum mengoptimalkan, menciptakan 20 + MB objek untuk memproses ~ 50 baris data. Ini bagus dalam pengujian, hingga Anda meningkatkan hingga seratus permintaan per menit dan tiba-tiba Anda membuat 2GB data per menit. Jika Anda ingin melakukan 20 reqs / detik Anda membuat 400MB objek dan kemudian membuangnya. 20 reqs / detik kecil untuk server yang layak.
sumber
while(something) { byte[] buffer = new byte[10240]; ... readIntoBuffer(buffer); ...
yang mungkin boros dibandingkan dengan misalnyabyte[] buffer = new byte[10240]; while(something) { ... readIntoBuffer(buffer); ...
.Sebenarnya, karena strategi manajemen memori yang dimungkinkan oleh bahasa Jawa (atau bahasa yang dikelola lainnya), pembuatan objek sedikit lebih banyak daripada penambahan pointer di blok memori yang disebut generasi muda. Ini jauh lebih cepat daripada C, di mana pencarian untuk memori bebas harus dilakukan.
Bagian lain dari biaya adalah penghancuran objek, tetapi sulit untuk dibandingkan dengan C. Biaya koleksi didasarkan pada jumlah objek yang disimpan jangka panjang tetapi frekuensi koleksi didasarkan pada jumlah objek yang dibuat ... di pada akhirnya, ini masih jauh lebih cepat daripada manajemen memori C-style.
sumber
Point
objek bisa muat di 2 register tujuan umum).Poster-poster lain dengan tepat menunjukkan bahwa pembuatan objek sangat cepat di Jawa, dan Anda biasanya tidak perlu khawatir tentang hal itu dalam aplikasi Java normal.
Ada beberapa situasi yang sangat khusus di mana adalah merupakan ide yang baik untuk menghindari pembuatan obyek.
sumber
Ada inti kebenaran dalam apa yang dikatakan rekan Anda. Saya dengan hormat menyarankan masalah dengan pembuatan objek sebenarnya adalah pengumpulan sampah . Dalam C ++ programmer dapat mengontrol dengan tepat bagaimana memori dialokasikan. Program ini dapat mengakumulasi crud selama atau sesingkat yang diinginkannya. Selanjutnya, program C ++ dapat membuang crud menggunakan utas yang berbeda dari yang membuatnya. Dengan demikian utas yang saat ini berfungsi tidak pernah berhenti untuk membersihkan.
Sebaliknya, Java Virtual Machine (JVM) secara berkala menghentikan kode Anda untuk mendapatkan kembali memori yang tidak digunakan. Sebagian besar pengembang Java tidak pernah memperhatikan jeda ini, karena biasanya jarang dan sangat singkat. Semakin kasar Anda menumpuk atau semakin dibatasi JVM Anda, semakin sering jeda ini terjadi. Anda dapat menggunakan alat seperti VisualVM untuk memvisualisasikan proses ini.
Dalam versi terbaru Java, algoritma pengumpulan sampah (GC) dapat disetel . Sebagai aturan umum, semakin pendek Anda ingin membuat jeda, semakin mahal biaya overhead di mesin virtual (yaitu CPU dan memori yang dihabiskan mengoordinasikan proses GC).
Kapan hal ini penting? Setiap kali Anda peduli dengan tingkat respons sub-milidetik yang konsisten, Anda akan peduli dengan GC. Sistem perdagangan otomatis yang ditulis dalam Java sangat menyempurnakan JVM untuk meminimalkan jeda. Perusahaan yang sebaliknya akan menulis Java beralih ke C ++ dalam situasi di mana sistem harus sangat responsif sepanjang waktu.
Sebagai catatan, saya tidak memaafkan penghindaran objek secara umum! Default untuk pemrograman berorientasi objek. Sesuaikan pendekatan ini hanya jika GC menghalangi Anda, dan kemudian hanya setelah mencoba menyetel JVM untuk berhenti sebentar. Buku bagus tentang penyetelan kinerja Java adalah Java Performance oleh Charlie Hunt dan Binu John.
sumber
Ada satu kasus di mana Anda mungkin berkecil dari membuat terlalu banyak objek di Jawa karena perancangan overhead untuk kinerja pada platform Android
Selain itu, jawaban di atas juga berlaku.
sumber
GC disetel untuk banyak objek berumur pendek
yang mengatakan jika Anda dapat dengan mudah mengurangi alokasi objek Anda harus
salah satu contoh akan membangun string dalam satu lingkaran, cara yang naif adalah
yang membuat
String
objek baru pada setiap+=
operasi (ditambah aStringBuilder
dan array char yang mendasarinya baru)Anda dapat dengan mudah menulis ulang ini menjadi:
pola ini (hasil yang tidak berubah dan nilai tengah lokal yang bisa berubah) dapat diterapkan untuk hal-hal lain juga
tetapi selain itu Anda harus menarik profiler untuk menemukan hambatan sebenarnya daripada mengejar hantu
sumber
StringBuilder
pendekatan adalah pra-ukuran yangStringBuilder
sehingga tidak harus mengalokasikan array yang mendasari denganStringBuilder(int)
konstruktor. Ini menjadikannya alokasi tunggal , bukan1+N
alokasi.Joshua Bloch (salah satu pembuat platform Java) menulis dalam bukunya, Java Efektif pada tahun 2001:
sumber
Ini sangat tergantung pada aplikasi spesifik, sehingga sangat sulit untuk mengatakan secara umum. Namun, saya akan cukup terkejut jika penciptaan objek sebenarnya merupakan hambatan kinerja dalam suatu aplikasi. Meskipun lambat, manfaat gaya kode mungkin akan lebih besar daripada kinerjanya (kecuali jika itu benar-benar terlihat oleh pengguna)
Dalam kasus apa pun, Anda bahkan tidak perlu khawatir tentang hal-hal ini sampai Anda telah membuat profil kode Anda untuk menentukan hambatan kinerja yang sebenarnya alih-alih menebak. Sampai saat itu, Anda harus melakukan apa pun yang terbaik untuk keterbacaan kode, bukan kinerja.
sumber
Saya pikir kolega Anda pasti mengatakan dari perspektif penciptaan objek yang tidak perlu. Maksud saya jika Anda sering membuat objek yang sama maka lebih baik membagikan objek itu. Bahkan dalam kasus-kasus di mana pembuatan objek menjadi kompleks dan membutuhkan lebih banyak memori, Anda mungkin ingin mengkloning objek itu dan menghindari membuat proses pembuatan objek yang kompleks (Tapi itu tergantung pada kebutuhan Anda). Saya pikir pernyataan "Pembuatan objek itu mahal" harus diambil dalam konteks.
Sejauh menyangkut persyaratan memori JVM, tunggu Java 8, Anda bahkan tidak perlu menentukan -Xmx, pengaturan ruang meta akan mengurus kebutuhan memori JVM dan akan tumbuh secara otomatis.
sumber
Ada lebih banyak hal untuk membuat kelas daripada mengalokasikan memori. Ada juga inisialisasi, saya tidak yakin mengapa bagian itu tidak tercakup oleh semua jawaban. Kelas normal mengandung beberapa variabel, dan melakukan beberapa bentuk inisialisasi, dan itu tidak gratis. Bergantung pada apa kelasnya, ia dapat membaca file, atau melakukan sejumlah operasi lambat lainnya.
Jadi pertimbangkan saja apa yang dikerjakan oleh konstruktor kelas, sebelum memperkirakan apakah itu gratis atau tidak.
sumber
Java GC sebenarnya sangat dioptimalkan dalam hal menciptakan banyak objek dengan cepat dengan cara "meledak". Dari apa yang saya mengerti mereka menggunakan pengalokasi sekuensial (pengalokasi O tercepat (1) tercepat dan paling sederhana untuk permintaan berukuran variabel) untuk "siklus ledakan" ke dalam ruang memori yang mereka sebut "ruang Eden", dan hanya jika objek tetap ada setelah siklus GC mereka pindah ke tempat di mana GC dapat mengumpulkannya satu per satu.
Dengan itu, jika kebutuhan kinerja Anda menjadi cukup kritis (seperti yang diukur dengan persyaratan pengguna-akhir yang nyata), maka objek melakukan overhead tetapi saya tidak akan memikirkannya begitu banyak dalam hal penciptaan / alokasi. Ini lebih berkaitan dengan lokalitas referensi dan ukuran tambahan dari semua objek di Jawa yang diperlukan untuk mendukung konsep-konsep seperti refleksi dan pengiriman dinamis (
Float
lebih besar darifloat
, sering sekitar 4 kali lebih besar pada 64-bit dengan persyaratan perataan, dan arrayFloat
tidak selalu dijamin untuk disimpan bersebelahan dari apa yang saya mengerti).Salah satu hal paling menarik yang pernah saya lihat dikembangkan di Jawa yang membuat saya menganggapnya sebagai pesaing berat di bidang saya (VFX) adalah pelacak jalur standar multithreaded interaktif (tidak menggunakan caching irradian atau BDPT atau MLS atau apa pun) di CPU menyediakan pratinjau waktu-nyata yang konvergen lebih cepat ke gambar bebas-noise. Saya telah bekerja dengan para profesional di C ++ mendedikasikan karir mereka untuk hal-hal seperti itu dengan profiler mewah di tangan yang mengalami kesulitan melakukan itu.
Tapi saya mengintip kode sumber dan sementara itu menggunakan banyak objek dengan biaya sepele, bagian paling penting dari pelacak jalur (BVH dan segitiga dan bahan) sangat jelas dan sengaja menghindari objek yang mendukung array besar tipe primitif ( kebanyakan
float[]
danint[]
), yang membuatnya menggunakan memori jauh lebih sedikit dan menjamin lokalitas spasial untuk mendapatkan dari satufloat
dalam array ke yang berikutnya. Saya tidak berpikir itu terlalu spekulatif untuk berpikir bahwa, jika penulis menggunakan tipe kotak sukaFloat
di sana, itu akan datang pada biaya yang agak besar untuk kinerjanya. Tapi kita sedang berbicara bagian yang paling kritis dari mesin itu, dan saya cukup yakin, mengingat betapa terampilnya pengembang mengoptimalkannya, bahwa dia mengukurnya dan menerapkan optimasi itu dengan sangat, sangat bijaksana, karena dia dengan senang hati menggunakan objek di tempat lain dengan biaya sepele untuk pelacak jalur realtime yang mengesankan.Bahkan di bidang yang sangat kritis terhadap kinerja seperti milik saya, Anda tidak akan menulis produk yang efisien jika Anda melukai diri sendiri di tempat-tempat yang tidak penting. Saya bahkan akan membuat klaim bahwa bidang yang paling kritis terhadap kinerja mungkin menempatkan permintaan yang lebih tinggi untuk produktivitas, karena kita membutuhkan semua waktu ekstra yang bisa kita dapatkan untuk menyetel titik-titik panas yang benar-benar penting dengan tidak membuang-buang waktu pada hal-hal yang tidak . Seperti contoh jejak lacak dari atas, penulis dengan terampil dan bijaksana menerapkan optimisasi semacam itu hanya ke tempat-tempat yang benar-benar penting, dan mungkin di belakang setelah pengukuran, dan masih dengan senang hati menggunakan objek di tempat lain.
sumber
float[]
vsFloat[]
, di mana pemrosesan satu juta dari yang sebelumnya secara berurutan mungkin relatif lebih cepat daripada yang kedua.Seperti yang orang katakan, pembuatan objek bukan biaya besar di Jawa (tapi saya bertaruh lebih besar dari operasi paling sederhana seperti menambahkan, dll) dan Anda tidak boleh menghindarinya terlalu banyak.
Itu mengatakan itu masih biaya, dan kadang-kadang Anda mungkin menemukan diri Anda mencoba untuk memo objek sebanyak mungkin. Tetapi hanya setelah profiling menunjukkan bahwa ini adalah masalah.
Berikut ini adalah presentasi yang bagus mengenai topik ini: https://www.cs.virginia.edu/kim/publicity/pldi09tutorials/memory-efisien-java-tutorial.pdf
sumber
Saya melakukan microbenchmark cepat tentang ini dan saya telah menyediakan sumber lengkap di github. Kesimpulan saya adalah apakah membuat objek itu mahal atau tidak bukan masalah, tetapi terus-menerus membuat objek dengan anggapan bahwa GC akan menangani hal-hal untuk Anda akan membuat aplikasi Anda memicu proses GC lebih cepat. GC adalah proses yang sangat mahal dan yang terbaik adalah menghindarinya sedapat mungkin dan tidak mencoba mendorongnya untuk memulai.
sumber