Apakah ada fungsi inline di java?


112

Apakah ada konsep fungsi inline di java, atau ada yang diganti? Jika ada, bagaimana cara menggunakannya? Saya pernah mendengarnya public, staticdan finalmetode adalah fungsi inline. Bisakah kita membuat fungsi inline kita sendiri?


4
Sekadar klarifikasi, maksud Anda en.wikipedia.org/wiki/Inline_function , bukan en.wikipedia.org/wiki/Anonymous_function , bukan?
JW.

3
Sebagai komentar kecil, pengoptimalan prematur adalah akar dari segala kejahatan. Tanpa sepenuhnya memahami sifat publik, statis, dan final, Anda tidak dapat benar-benar memahami dampak inlining yang mungkin ditimbulkan - dan itu bergantung pada JVM yang Anda gunakan. Pastikan untuk menjawab pertama mengapa Anda perlu menyebariskan sesuatu: hampir pasti ada pengoptimalan ROI yang lebih tinggi yang dapat Anda lakukan di tempat lain.
Nathaniel Ford

Jawaban:


123

Di Java, pengoptimalan biasanya dilakukan di level JVM. Saat runtime, JVM melakukan beberapa analisis "rumit" untuk menentukan metode mana yang akan disebariskan. Ini bisa menjadi agresif dalam membuat sebaris, dan JVM Hotspot sebenarnya bisa sebaris metode non-final.

Kompiler java hampir tidak pernah melakukan inline pemanggilan metode apa pun (JVM melakukan semua itu saat runtime). Mereka melakukan konstanta waktu kompilasi sebaris (misalnya nilai primitif statis akhir). Tapi bukan metodenya.

Untuk lebih banyak sumber:

  1. Artikel: Mesin Kinerja HotSpot Java: Contoh Metode Inlining

  2. Wiki: Sebaris di OpenJDK , tidak terisi penuh tetapi berisi tautan ke diskusi yang berguna.


15

Tidak, tidak ada fungsi inline di java. Ya, Anda dapat menggunakan metode statis publik di mana saja dalam kode saat ditempatkan di kelas publik. Kompilator java dapat melakukan ekspansi sebaris dengan metode statis atau final, tetapi itu tidak dijamin.

Biasanya pengoptimalan kode seperti itu dilakukan oleh kompilator dalam kombinasi dengan JVM / JIT / HotSpot untuk segmen kode yang sangat sering digunakan. Juga konsep optimasi lain seperti deklarasi register parameter tidak dikenal di java.

Pengoptimalan tidak dapat dipaksakan dengan deklarasi di java, tetapi dilakukan oleh compiler dan JIT. Dalam banyak bahasa lain, deklarasi ini seringkali hanya berupa petunjuk kompilator (Anda dapat mendeklarasikan lebih banyak parameter register daripada yang dimiliki prosesor, sisanya diabaikan).

Mendeklarasikan metode java statis, final atau private juga merupakan petunjuk untuk compiler. Anda harus menggunakannya, tetapi tidak ada jaminan. Kinerja Java bersifat dinamis, tidak statis. Panggilan pertama ke sistem selalu lambat karena pemuatan kelas. Panggilan berikutnya lebih cepat, tetapi bergantung pada memori dan waktu proses, panggilan yang paling umum dioptimalkan dalam sistem yang sedang berjalan, sehingga server dapat menjadi lebih cepat selama waktu proses!


3
finaltidak berdampak pada JIT inlining
Steve Kuo

1
+1, Tetapi bagaimana kita dapat menguji apakah versi terkompilasi dari suatu metode inline?
Pacerier

@Pacerier Tapi mengapa kita harus menguji apakah ada sesuatu yang sebaris?
Arne Burmeister

14

Java tidak menyediakan cara untuk menyarankan secara manual bahwa metode harus sebaris. Seperti yang dikatakan @notnoop di komentarnya, penyebarisan biasanya dilakukan oleh JVM pada waktu eksekusi.


3
Kebanyakan kompiler java tidak pernah memanggil metode sebaris. Kebanyakan JVM melakukan itu.
notnoop

Terima kasih telah menjelaskannya. Saya tidak yakin persisnya fase apa yang terjadi. Saya akan mengedit posting saya untuk mencerminkan itu.
Thomas Owens

@ThomasOwens memang begitu, tapi ini bukan untuk umumjdk.internal.vm.annotation.ForceInline
Eugene

4

Apa yang Anda katakan di atas benar. Terkadang metode terakhir dibuat sebagai inline, tetapi tidak ada cara lain untuk secara eksplisit membuat fungsi inline di java.


5
Metode terakhir tidak dijamin sebagai metode inline.
Thomas Owens

4
Di HotSpot, menambahkan finalbahkan tidak membuat perbedaan apa pun, apakah metode tersebut inline atau tidak.
Tom Hawtin - tackline

4
@ Thomas - itulah sebabnya saya mengatakan "Terkadang metode terakhir ..."
Greenieie

@ TomHawtin-tackline apakah Anda memiliki sumber resmi untuk itu? Sejauh yang saya tahu, metode terakhir dapat disisipkan tanpa menggunakan pelindung tipe, yang berarti bahwa pengubah membuat metode sebaris lebih efisien daripada tanpa pengubah. Saya tahu bahwa Jikes RVM mempertimbangkan hal ini saat memutuskan apakah akan sebaris. Apakah Anda yakin HotSpot tidak melakukan sesuatu yang serupa?
Jannik Jochem

2

Contoh kehidupan nyata:

public class Control {
    public static final long EXPIRED_ON = 1386082988202l;
    public static final boolean isExpired() {
        return (System.currentTimeMillis() > EXPIRED_ON);
    }
}

Kemudian di kelas lain, saya dapat keluar jika kodenya telah kedaluwarsa. Jika saya mereferensikan variabel EXPIRED_ON dari kelas lain, konstanta inline ke kode byte, sehingga sangat sulit untuk melacak semua tempat di kode yang memeriksa tanggal kedaluwarsa. Namun, jika kelas lain memanggil metode isExpired (), metode sebenarnya dipanggil, yang berarti peretas dapat mengganti metode isExpired dengan metode lain yang selalu mengembalikan false.

Saya setuju akan sangat baik untuk memaksa kompiler untuk menyebariskan metode akhir statis ke semua kelas yang mereferensikannya. Dalam hal ini, Anda bahkan tidak perlu menyertakan kelas Kontrol, karena kelas tersebut tidak diperlukan pada waktu proses.

Dari penelitian saya, hal ini tidak bisa dilakukan. Mungkin beberapa alat Obfuscator dapat melakukan ini, atau, Anda dapat memodifikasi proses build Anda untuk mengedit sumber sebelum dikompilasi.

Adapun untuk membuktikan jika metode dari kelas kontrol ditempatkan sebaris ke kelas lain selama kompilasi, coba jalankan kelas lain tanpa kelas Kontrol di classpath.


2

Nah, ada metode yang bisa disebut metode "inline" di java, tetapi tergantung pada jvm. Setelah dikompilasi, jika kode mesin metode kurang dari 35 byte, itu akan segera ditransfer ke metode inline, jika kode mesin metode kurang dari 325 byte, itu dapat ditransfer ke metode inline, tergantung pada jvm.


1
Ini adalah nilai default untuk VM Oracle, lihat docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html
rmuller

0

jadi, sepertinya tidak ada, tetapi Anda dapat menggunakan solusi ini menggunakan guava atau implementasi kelas Fungsi yang setara, karena kelas itu sangat sederhana, mis .:

    assert false : new com.google.common.base.Function<Void,String>(){
        @Override public String apply(Void input) {
            //your complex code go here
            return "weird message";
        }}.apply(null);

ya, ini adalah kode mati hanya untuk memberi contoh cara membuat blok kode kompleks (dalam {}) untuk melakukan sesuatu yang begitu spesifik yang seharusnya tidak mengganggu kita dalam membuat metode apapun untuk itu, AKA inline!


Sepertinya ide yang masuk akal. Apakah Anda memiliki versi ini yang tidak menggunakan perpustakaan umum google?
ragerdl

0

Java9 memiliki kompilator "Ahead of time" yang melakukan beberapa pengoptimalan pada waktu kompilasi, bukan waktu proses, yang dapat dilihat sebagai sebaris.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.