Apakah ada manfaat kinerja dengan satu atau lain cara? Apakah compiler / VM spesifik? Saya menggunakan Hotspot.
java
performance
premature-optimization
Andy Faibishenko
sumber
sumber
Empat tahun kemudian...
Oke, dengan harapan dapat menjawab pertanyaan ini sekali dan selamanya, saya telah menulis sebuah patokan yang menunjukkan bagaimana berbagai jenis panggilan (virtual, non-virtual, statis) dibandingkan satu sama lain.
Saya menjalankannya dengan ideone , dan inilah yang saya dapatkan:
(Jumlah iterasi yang lebih besar lebih baik.)
Seperti yang diharapkan, panggilan metode virtual adalah yang paling lambat, panggilan metode non-virtual lebih cepat, dan panggilan metode statis bahkan lebih cepat.
Apa yang tidak saya harapkan adalah perbedaannya menjadi begitu jelas: Panggilan metode virtual diukur untuk berjalan kurang dari setengah kecepatan panggilan metode non-virtual, yang pada gilirannya diukur untuk menjalankan keseluruhan 15% lebih lambat daripada panggilan statis. Itulah yang ditunjukkan oleh pengukuran ini; perbedaan aktual sebenarnya harus sedikit lebih jelas, karena untuk setiap panggilan metode virtual, nonvirtual, dan statis, kode pembandingan saya memiliki overhead konstan tambahan untuk menambah satu variabel integer, memeriksa variabel boolean, dan mengulang jika tidak benar.
Saya kira hasilnya akan bervariasi dari CPU ke CPU, dan dari JVM ke JVM, jadi cobalah dan lihat apa yang Anda dapatkan:
Perlu dicatat bahwa perbedaan kinerja ini hanya berlaku untuk kode yang tidak melakukan apa pun selain menjalankan metode tanpa parameter. Kode lain apa pun yang Anda miliki di antara pemanggilan akan mengurangi perbedaan, dan ini termasuk penerusan parameter. Sebenarnya, perbedaan 15% antara panggilan statis dan nonvirtual mungkin dijelaskan secara lengkap oleh fakta bahwa
this
pointer tidak harus diteruskan ke metode statis. Jadi, hanya perlu sedikit kode yang melakukan hal-hal sepele di antara panggilan untuk perbedaan antara berbagai jenis panggilan yang akan diencerkan hingga tidak memiliki dampak bersih sama sekali.Juga, panggilan metode virtual ada karena suatu alasan; mereka memang memiliki tujuan untuk melayani, dan mereka diimplementasikan menggunakan cara paling efisien yang disediakan oleh perangkat keras yang mendasarinya. (Set instruksi CPU.) Jika, dalam keinginan Anda untuk menghilangkannya dengan menggantinya dengan panggilan nonvirtual atau statis, Anda akhirnya harus menambahkan sebanyak sedikit kode tambahan untuk meniru fungsinya, maka overhead bersih yang Anda hasilkan terikat menjadi tidak kurang, tetapi lebih. Sangat mungkin, sangat banyak, sangat banyak.
sumber
VirtualTest | 488846733 -- NonVirtualTest | 480530022 -- StaticTest | 484353198
pada instalasi OpenJDK saya. FTR: Itu bahkan benar jika saya menghapusfinal
pengubahnya. Btw. Saya harus membuatterminate
lapanganvolatile
, jika tidak tes tidak selesai.VirtualTest | 12451872 -- NonVirtualTest | 12089542 -- StaticTest | 8181170
. Tidak hanya OpenJDK di notebook saya yang berhasil melakukan 40x lebih banyak iterasi, pengujian statis selalu memiliki throughput sekitar 30% lebih sedikit. Ini mungkin fenomena khusus ART, karena saya mendapatkan hasil yang diharapkan pada tablet Android 4.4:VirtualTest | 138183740 -- NonVirtualTest | 142268636 -- StaticTest | 161388933
Nah, panggilan statis tidak dapat diganti (jadi selalu kandidat untuk sebaris), dan tidak memerlukan pemeriksaan nullity apa pun. HotSpot melakukan banyak pengoptimalan keren untuk metode contoh yang mungkin meniadakan keuntungan ini, tetapi itu mungkin alasan mengapa panggilan statis bisa lebih cepat.
Namun, itu seharusnya tidak memengaruhi desain Anda - kode dengan cara yang paling mudah dibaca dan alami - dan hanya khawatir tentang pengoptimalan mikro semacam ini jika Anda memiliki penyebabnya (yang hampir tidak akan pernah Anda lakukan ).
sumber
Ini adalah compiler / VM tertentu.
Oleh karena itu, mungkin tidak perlu dirisaukan kecuali Anda telah mengidentifikasi ini sebagai masalah kinerja yang benar-benar kritis dalam aplikasi Anda. Pengoptimalan dini adalah akar dari semua kejahatan, dll.
Namun saya telah melihat pengoptimalan ini memberikan peningkatan kinerja yang substansial dalam situasi berikut:
Jika hal di atas berlaku untuk Anda, mungkin perlu diuji.
Ada juga satu alasan bagus lainnya (dan berpotensi bahkan lebih penting!) Untuk menggunakan metode statis - jika metode tersebut benar-benar memiliki semantik statis (yaitu secara logis tidak terhubung ke instance kelas tertentu) maka masuk akal untuk membuatnya statis untuk mencerminkan fakta ini. Pemrogram Java yang berpengalaman kemudian akan melihat pengubah statis dan langsung berpikir "aha! Metode ini statis sehingga tidak memerlukan instance dan mungkin tidak memanipulasi status instance tertentu". Jadi Anda akan mengkomunikasikan sifat statis dari metode ini secara efektif ....
sumber
Seperti yang dikatakan poster sebelumnya: Ini sepertinya pengoptimalan yang prematur.
Namun, ada satu perbedaan (bagian dari fakta bahwa pemanggilan non-statis memerlukan dorongan tambahan dari objek callee ke tumpukan operan):
Karena metode statis tidak dapat diganti, tidak akan ada pencarian virtual dalam waktu proses untuk panggilan metode statis. Ini dapat menghasilkan perbedaan yang dapat diamati dalam beberapa keadaan.
Perbedaan pada tingkat kode byte adalah bahwa pemanggilan metode non-statis dilakukan melalui
INVOKEVIRTUAL
,INVOKEINTERFACE
atauINVOKESPECIAL
sementara pemanggilan metode statis dilakukan melaluiINVOKESTATIC
.sumber
invokespecial
karena bukan virtual.Sangat tidak mungkin bahwa perbedaan apa pun dalam kinerja panggilan statis versus panggilan non-statis membuat perbedaan dalam aplikasi Anda. Ingatlah bahwa "pengoptimalan prematur adalah akar dari segala kejahatan".
sumber
7 tahun kemudian ...
Saya tidak terlalu yakin dengan hasil yang ditemukan Mike Nakis karena hasil tersebut tidak membahas beberapa masalah umum yang berkaitan dengan pengoptimalan Hotspot. Saya telah menginstrumentasi tolok ukur menggunakan JMH dan menemukan overhead metode instans menjadi sekitar 0,75% di mesin saya vs panggilan statis. Mengingat overhead yang rendah, saya pikir kecuali dalam operasi yang paling sensitif latensi, ini bisa dibilang bukan perhatian terbesar dalam desain aplikasi. Hasil ringkasan dari benchmark JMH saya adalah sebagai berikut;
Anda dapat melihat kode di sini di Github;
https://github.com/nfisher/svsi
Tolok ukur itu sendiri cukup sederhana tetapi bertujuan untuk meminimalkan penghapusan kode mati dan pelipatan konstan. Mungkin ada optimisasi lain yang saya lewatkan / abaikan dan hasil ini cenderung bervariasi per rilis JVM dan OS.
sumber
ops/s
terutama di lingkungan ART (misalnya penggunaan memori, pengurangan ukuran file .oat, dll). Apakah Anda mengetahui alat / cara yang relatif sederhana yang dapat dicoba untuk mengukur metrik lain ini?Untuk keputusan jika suatu metode harus statis, aspek kinerja harus tidak relevan. Jika Anda memiliki masalah kinerja, membuat banyak metode statis tidak akan menghemat waktu. Meskipun demikian, metode statis hampir pasti tidak lebih lambat daripada metode instance mana pun, dalam banyak kasus sedikit lebih cepat :
1.) Metode statis tidak polimorfik, sehingga JVM memiliki lebih sedikit keputusan yang harus dibuat untuk menemukan kode yang sebenarnya untuk dieksekusi. Ini adalah titik diperdebatkan di Age of Hotspot, karena Hotspot akan mengoptimalkan panggilan metode instance yang hanya memiliki satu situs implementasi, sehingga mereka akan melakukan hal yang sama.
2.) Perbedaan halus lainnya adalah bahwa metode statis jelas tidak memiliki referensi "ini". Ini menghasilkan bingkai tumpukan satu slot lebih kecil daripada metode instance dengan tanda tangan dan isi yang sama ("ini" diletakkan di slot 0 dari variabel lokal pada tingkat bytecode, sedangkan untuk metode statis slot 0 digunakan untuk yang pertama parameter metode).
sumber
Mungkin ada perbedaan, dan mungkin berlaku untuk bagian kode tertentu, dan mungkin berubah bahkan dengan rilis kecil JVM.
Ini pasti bagian dari 97% efisiensi kecil yang harus Anda lupakan .
sumber
TableView
jutaan catatan.Secara teori, lebih murah.
Inisialisasi statis akan dilakukan meskipun Anda membuat instance objek, sedangkan metode statis tidak akan melakukan inisialisasi apa pun yang biasanya dilakukan dalam konstruktor.
Namun, saya belum menguji ini.
sumber
Seperti yang dicatat Jon, metode statis tidak dapat diganti, jadi dengan hanya memanggil metode statis mungkin - pada runtime Java yang cukup naif - lebih cepat daripada memanggil metode instance.
Tapi kemudian, bahkan dengan asumsi Anda berada pada titik di mana Anda peduli untuk mengacaukan desain Anda untuk menghemat beberapa nanodetik, itu hanya memunculkan pertanyaan lain: apakah Anda memerlukan metode untuk mengganti diri Anda sendiri? Jika Anda mengubah kode Anda untuk membuat metode contoh menjadi metode statis untuk menyimpan nanodetik di sana-sini, dan kemudian berbalik dan menerapkan dispatcher Anda sendiri di atas itu, Anda hampir pasti akan kurang efisien daripada yang dibangun ke dalam runtime Java Anda.
sumber
Saya ingin menambahkan jawaban hebat lainnya di sini yang juga bergantung pada aliran Anda, misalnya:
Perhatikan bahwa Anda membuat objek MyRowMapper baru untuk setiap panggilan.
Sebagai gantinya, saya menyarankan untuk menggunakan bidang statis di sini.
sumber