Seperti yang tertulis di JEP 280: Indify String Concatenation :
Ubah
String
urutan bytecode -concatenation statis yang dihasilkan olehjavac
untuk menggunakaninvokedynamic
panggilan ke fungsi library JDK. Ini akan memungkinkan pengoptimalanString
penggabungan di masa mendatang tanpa memerlukan perubahan lebih lanjut pada bytecode yang dikeluarkan olehjavac
.
Di sini saya ingin memahami apa kegunaan invokedynamic
panggilan dan bagaimana penggabungan bytecode berbeda dari invokedynamic
?
java
string
string-concatenation
java-9
invokedynamic
Mohit Tyagi
sumber
sumber
Jawaban:
Cara "lama" menghasilkan banyak
StringBuilder
operasi yang berorientasi. Pertimbangkan program ini:Jika kita mengkompilasinya dengan JDK 8 atau sebelumnya dan kemudian menggunakan
javap -c Example
untuk melihat bytecode, kita akan melihat sesuatu seperti ini:Seperti yang Anda lihat, ini membuat
StringBuilder
dan menggunakanappend
. Ini terkenal cukup tidak efisien karena kapasitas default buffer internalStringBuilder
hanya 16 karakter, dan tidak ada cara bagi compiler untuk mengetahui mengalokasikan lebih banyak, sehingga akhirnya harus mengalokasikan ulang. Ini juga banyak panggilan metode. (Perhatikan bahwa JVM terkadang dapat mendeteksi dan menulis ulang pola panggilan ini untuk membuatnya lebih efisien.)Mari kita lihat apa yang dihasilkan Java 9:
Ya ampun, tapi itu lebih pendek. :-) Itu membuat satu panggilan ke
makeConcatWithConstants
dariStringConcatFactory
, yang mengatakan ini di Javadoc-nya:sumber
+=
di loop for mereka. Saya mengatakan kepada mereka itu tergantung, tetapi jangan lupa bahwa mereka mungkin menemukan cara yang lebih baik untuk merangkai concat suatu saat nanti. Garis kuncinya sebenarnya adalah garis kedua dari belakang:So by being smart, you have caused a performance hit when Java got smarter than you.
invokedynamic
memungkinkan strategi penggabungan yang berbeda untuk dipilih pada waktu proses dan terikat pada pemanggilan pertama, tanpa overhead dari pemanggilan metode dan tabel pengiriman pada setiap pemanggilan; lebih lanjut di artikel nicolai di sini dan di JEP .Object
, tapi kemudian Anda harus mengemas semua primitif ... (Yang Nicolai liput dalam artikelnya yang sangat bagus, btw.)String.concat(String)
metode yang sudah ada yang implementasinya menciptakan array string yang dihasilkan di tempat. Keuntungannya menjadi diperdebatkan ketika kita harus memanggiltoString()
objek sewenang-wenang. Demikian juga, saat memanggil metode yang menerima larik, pemanggil harus membuat dan mengisi larik yang mengurangi manfaat secara keseluruhan. Tapi sekarang, itu tidak relevan, karena solusi baru pada dasarnya adalah apa yang Anda pertimbangkan, kecuali bahwa ia tidak memiliki overhead tinju, tidak memerlukan pembuatan array, dan backend dapat menghasilkan penangan yang dioptimalkan untuk skenario tertentu.Sebelum masuk ke detail
invokedynamic
implementasi yang digunakan untuk optimasi penggabungan String, menurut pendapat saya, seseorang harus mendapatkan beberapa latar belakang tentang Apa yang dipanggil dan bagaimana cara menggunakannya?Saya mungkin akan mencoba dan membawa Anda melalui ini dengan perubahan yang dibawa untuk implementasi optimasi penggabungan String.
Mendefinisikan Metode Bootstrap : - Dengan Java9, metode bootstrap untuk
invokedynamic
situs panggilan, untuk mendukung penggabungan string terutamamakeConcat
danmakeConcatWithConstants
diperkenalkan denganStringConcatFactory
implementasi.Penggunaan invokedynamic memberikan alternatif untuk memilih strategi terjemahan hingga runtime. Strategi terjemahan yang digunakan
StringConcatFactory
mirip dengan yangLambdaMetafactory
diperkenalkan pada versi java sebelumnya. Selain itu, salah satu tujuan JEP yang disebutkan dalam pertanyaan tersebut adalah untuk memperluas strategi ini lebih jauh.Menentukan Entri Kumpulan Konstan : - Ini adalah argumen statis tambahan untuk
invokedynamic
instruksi selain (1)MethodHandles.Lookup
objek yang merupakan pabrik untuk membuat pegangan metode dalam konteksinvokedynamic
instruksi, (2)String
objek, nama metode yang disebutkan dalam panggilan dinamis situs dan (3)MethodType
objek, tanda tangan jenis yang diselesaikan dari situs panggilan dinamis.Ada yang sudah tertaut selama penautan kode. Saat runtime, metode bootstrap berjalan dan menautkan kode sebenarnya yang melakukan penggabungan. Ini menulis ulang
invokedynamic
panggilan dengan panggilan yang sesuaiinvokestatic
. Ini memuat string konstan dari kumpulan konstan, argumen statis metode bootstrap dimanfaatkan untuk meneruskan konstanta ini dan konstanta lainnya langsung ke panggilan metode bootstrap.Menggunakan Instruksi invokedynamic : - Ini menawarkan fasilitas untuk lazy linkage, dengan menyediakan sarana untuk mem-bootstrap target panggilan satu kali, selama pemanggilan awal. Ide konkret untuk pengoptimalan di sini adalah mengganti seluruh
StringBuilder.append
tarian denganinvokedynamic
panggilan sederhana kejava.lang.invoke.StringConcatFactory
, yang akan menerima nilai-nilai yang diperlukan untuk penggabungan.The Indify String concatenation negara usulan dengan contoh pembandingan aplikasi dengan Java9 mana metode yang sama seperti dimiliki oleh @TJ Crowder dikompilasi dan perbedaan dalam bytecode ini cukup terlihat antara pelaksanaan yang bervariasi.
sumber
Saya akan sedikit menambahkan sedikit detail di sini. Bagian utama untuk mendapatkan adalah bagaimana penggabungan string dilakukan adalah keputusan runtime, bukan waktu kompilasi lagi . Dengan demikian dapat berubah, artinya Anda telah mengkompilasi kode Anda sekali terhadap java-9 dan dapat mengubah implementasi yang mendasarinya sesuka hati, tanpa perlu melakukan kompilasi ulang.
Dan poin kedua adalah saat ini ada
6 possible strategies for concatenation of String
:Anda dapat memilih salah satu dari mereka melalui parameter:
-Djava.lang.invoke.stringConcat
. Perhatikan bahwaStringBuilder
masih ada pilihan.sumber