Tema berulang pada SE yang saya perhatikan dalam banyak pertanyaan adalah argumen yang sedang berlangsung bahwa C ++ lebih cepat dan / atau lebih efisien daripada bahasa tingkat yang lebih tinggi seperti Java. Argumen tandingannya adalah bahwa JVM atau CLR modern dapat sama efisiennya berkat JIT dan seterusnya untuk semakin banyak tugas dan bahwa C ++ semakin efisien jika Anda tahu apa yang Anda lakukan dan mengapa melakukan hal-hal dengan cara tertentu akan pantas meningkat kinerja. Itu jelas dan masuk akal.
Saya ingin tahu penjelasan dasar (jika ada hal seperti itu ...) mengapa dan bagaimana tugas-tugas tertentu lebih cepat di C ++ daripada JVM atau CLR? Apakah hanya karena C ++ dikompilasi ke dalam kode mesin sedangkan JVM atau CLR masih memiliki overhead pemrosesan kompilasi JIT pada saat run time?
Ketika saya mencoba untuk meneliti topik, semua yang saya temukan adalah argumen yang sama yang telah saya uraikan di atas tanpa informasi terperinci untuk memahami secara tepat bagaimana C ++ dapat digunakan untuk komputasi berkinerja tinggi.
sumber
Jawaban:
Ini semua tentang memori (bukan JIT). JIT 'keunggulan dibandingkan C' sebagian besar terbatas pada mengoptimalkan panggilan virtual atau non-virtual melalui inlining, sesuatu yang sudah dilakukan oleh CPU BTB.
Dalam mesin modern, mengakses RAM benar - benar lambat (dibandingkan dengan apa pun yang dilakukan CPU), yang berarti aplikasi yang menggunakan cache sebanyak mungkin (yang lebih mudah bila lebih sedikit memori digunakan) dapat mencapai seratus kali lebih cepat daripada yang jangan. Dan ada banyak cara di mana Java menggunakan lebih banyak memori daripada C ++ dan membuatnya lebih sulit untuk menulis aplikasi yang sepenuhnya mengeksploitasi cache:
Beberapa faktor lain yang berhubungan dengan memori tetapi tidak terkait cache:
Beberapa dari hal-hal ini adalah pengorbanan (tidak harus melakukan manajemen memori manual layak memberikan banyak kinerja bagi kebanyakan orang), beberapa mungkin merupakan hasil dari mencoba untuk menjaga Java tetap sederhana, dan beberapa kesalahan desain (walaupun mungkin hanya di belakang) , yaitu UTF-16 adalah penyandian panjang tetap ketika Java dibuat, yang membuat keputusan untuk memilihnya lebih mudah dimengerti).
Perlu dicatat bahwa banyak dari pengorbanan ini sangat berbeda untuk Java / JVM daripada untuk C # / CIL. NET CIL memiliki struct tipe referensi, alokasi stack / passing, array array struct, dan generik tipe-instantiated.
sumber
Sebagian, tetapi secara umum, dengan asumsi kompiler JIT state-of-the-art yang benar-benar fantastis, kode C ++ yang tepat masih cenderung berkinerja lebih baik daripada kode Java karena DUA alasan utama:
1) C ++ templat menyediakan fasilitas yang lebih baik untuk menulis kode yang generik DAN efisien . Template menyediakan bagi para programmer C ++ abstraksi yang sangat berguna yang memiliki overhead NOL runtime. (Template pada dasarnya mengkompilasi waktu bebek-mengetik.) Sebaliknya, yang terbaik yang Anda dapatkan dengan Java generics pada dasarnya adalah fungsi virtual. Fungsi virtual selalu memiliki overhead runtime, dan umumnya tidak dapat digariskan.
Secara umum, sebagian besar bahasa, termasuk Java, C # dan bahkan C, membuat Anda memilih antara efisiensi dan generalisasi / abstraksi. Templat C ++ memberi Anda keduanya (dengan biaya waktu kompilasi yang lebih lama).
2) Fakta bahwa standar C ++ tidak banyak bicara tentang tata letak biner dari program C ++ yang dikompilasi memberikan kompiler C ++ lebih banyak kelonggaran daripada kompiler Java, memungkinkan untuk optimasi yang lebih baik (dengan biaya terkadang lebih sulit dalam debugging kadang-kadang. ) Faktanya, sifat spesifik dari spesifikasi bahasa Jawa memberlakukan penalti kinerja di area tertentu. Misalnya, Anda tidak bisa memiliki array Objek yang berdekatan di Jawa. Anda hanya dapat memiliki array yang berdekatan dengan pointer Object(Referensi), yang berarti bahwa iterasi pada array di Jawa selalu menimbulkan biaya tipuan. Namun semantik nilai C ++, memungkinkan array yang berdekatan. Perbedaan lain adalah kenyataan bahwa C ++ memungkinkan objek untuk dialokasikan pada stack, sedangkan Java tidak, yang berarti bahwa, dalam praktiknya, karena sebagian besar program C ++ cenderung mengalokasikan objek pada stack, biaya alokasi seringkali mendekati nol.
Satu area di mana C ++ mungkin tertinggal di belakang Java adalah situasi di mana banyak objek kecil perlu dialokasikan di heap. Dalam hal ini, sistem pengumpulan sampah Jawa mungkin akan menghasilkan kinerja yang lebih baik daripada standar
new
dandelete
dalam C ++ karena Java GC memungkinkan deallokasi massal. Tetapi sekali lagi, seorang programmer C ++ dapat mengkompensasi hal ini dengan menggunakan kumpulan memori atau pengalokasi slab, sedangkan seorang programmer Java tidak memiliki jalan lain ketika dihadapkan dengan pola alokasi memori yang runtime Java tidak dioptimalkan untuk.Juga, lihat jawaban yang sangat bagus ini untuk informasi lebih lanjut tentang topik ini.
sumber
std::vector<int>
adalah array dinamis yang dirancang hanya untuk ints, dan kompiler dapat mengoptimalkannya. AC #List<int>
masih tetap aList
.List<int>
menggunakanint[]
, bukanObject[]
seperti Java. Lihat stackoverflow.com/questions/116988/...vector<N>
mana, untuk kasus spesifikvector<4>
, implementasi SIMD kode tangan saya harus digunakanApa yang jawaban lain (6 sejauh ini) tampaknya lupa untuk disebutkan, tetapi apa yang saya anggap sangat penting untuk menjawab ini, adalah salah satu filosofi desain dasar C ++, yang dirumuskan dan digunakan oleh Stroustrup sejak hari pertama:
Anda tidak membayar apa yang tidak Anda gunakan.
Ada beberapa prinsip desain mendasar yang penting lainnya yang sangat membentuk C ++ (seperti Anda tidak harus dipaksa ke dalam paradigma tertentu), tetapi Anda tidak membayar untuk apa yang tidak Anda gunakan ada di sana di antara yang paling penting.
Dalam bukunya The Design and Evolution of C ++ (biasanya disebut sebagai [D&E]), Stroustrup menjelaskan kebutuhan apa yang dia miliki yang membuatnya muncul dengan C ++. Dalam kata-kata saya sendiri: Untuk tesis PhD-nya (ada hubungannya dengan simulasi jaringan, IIRC), ia menerapkan sistem dalam SIMULA, yang sangat disukainya, karena bahasa itu sangat baik dalam memungkinkan dia untuk mengekspresikan pikirannya langsung dalam kode. Namun, program yang dihasilkan berjalan terlalu lambat, dan untuk mendapatkan gelar, ia menulis ulang hal itu di BCPL, pendahulu C. Menulis kode dalam BCPL yang ia gambarkan sebagai sesuatu yang menyakitkan, tetapi program yang dihasilkan cukup cepat untuk dikirim. hasil, yang memungkinkan dia untuk menyelesaikan gelar PhD.
Setelah itu, dia ingin bahasa yang memungkinkan untuk menerjemahkan masalah dunia nyata ke dalam kode secara langsung, tetapi juga memungkinkan kode menjadi sangat efisien.
Dalam mengejar itu, ia menciptakan apa yang nantinya menjadi C ++.
Jadi tujuan yang dikutip di atas bukan hanya salah satu dari beberapa prinsip desain dasar yang mendasar, itu sangat dekat dengan raison d'etre untuk C ++. Dan itu dapat ditemukan hampir di mana saja dalam bahasa ini: Fungsi hanya
virtual
ketika Anda menginginkannya (karena memanggil fungsi virtual disertai sedikit overhead) POD hanya diinisialisasi secara otomatis ketika Anda secara eksplisit meminta ini, pengecualian hanya membuat Anda kehilangan kinerja ketika Anda benar-benar membuangnya (padahal itu tujuan desain eksplisit untuk memungkinkan pengaturan / pembersihan stackframe menjadi sangat murah), tidak ada GC yang berjalan kapan pun rasanya, dll.C ++ secara eksplisit memilih untuk tidak memberi Anda kenyamanan ("apakah saya harus membuat metode ini virtual di sini?") Sebagai imbalan atas kinerja ("tidak, saya tidak, dan sekarang kompiler dapat
inline
dan mengoptimalkan cara keluar dari semuanya! "), dan, tidak mengherankan, ini memang menghasilkan peningkatan kinerja dibandingkan dengan bahasa yang lebih nyaman.sumber
Apakah Anda tahu makalah penelitian Google tentang topik itu?
Dari kesimpulan:
Ini setidaknya sebagian penjelasan, dalam arti "karena dunia nyata C + + kompiler menghasilkan kode lebih cepat daripada kompiler Jawa dengan langkah-langkah empiris".
sumber
Ini bukan duplikat dari pertanyaan Anda, tetapi jawaban yang diterima menjawab sebagian besar pertanyaan Anda: Tinjauan modern tentang Jawa
Untuk menyimpulkan:
Jadi, tergantung pada bahasa lain yang Anda bandingkan C ++, Anda mungkin mendapatkan atau tidak jawaban yang sama.
Di C ++ Anda memiliki:
Ini adalah fitur atau efek samping dari definisi bahasa yang membuatnya secara teori lebih efisien pada memori dan kecepatan daripada bahasa apa pun yang:
C ++ inlining agresif dari kompiler mengurangi atau menghilangkan banyak tipuan. Kapasitas untuk menghasilkan sekumpulan kecil data ringkas membuatnya ramah-cache jika Anda tidak menyebarkan data ini ke seluruh memori alih-alih dikemas bersama-sama (keduanya dimungkinkan, C ++ membiarkan Anda memilih). RAII membuat perilaku memori C ++ dapat diprediksi, menghilangkan banyak masalah jika simulasi real-time atau semi-real-time, yang membutuhkan kecepatan tinggi. Masalah lokalitas, secara umum dapat disimpulkan dengan ini: semakin kecil program / data, semakin cepat eksekusi. C ++ menyediakan beragam cara untuk memastikan data Anda berada di tempat yang Anda inginkan (di pool, array, atau apa pun) dan data itu kompak.
Jelas, ada bahasa lain yang dapat melakukan hal yang sama, tetapi mereka kurang populer karena mereka tidak menyediakan alat abstraksi sebanyak C ++, sehingga mereka kurang berguna dalam banyak kasus.
sumber
Ini terutama tentang memori (seperti kata Michael Borgwardt) dengan sedikit inefisiensi JIT.
Satu hal yang tidak disebutkan adalah cache - untuk menggunakan cache sepenuhnya, Anda perlu data Anda ditata secara bersamaan (yaitu semuanya bersama-sama). Sekarang dengan sistem GC, memori dialokasikan pada heap GC, yang cepat, tetapi ketika memori digunakan GC akan menendang secara teratur dan menghapus blok yang tidak lagi digunakan dan kemudian kompak sisanya. Sekarang terlepas dari lambatnya memindahkan blok yang digunakan bersama-sama, ini berarti bahwa data yang Anda gunakan mungkin tidak terjebak bersama. Jika Anda memiliki larik 1000 elemen, kecuali jika Anda mengalokasikan semuanya sekaligus (dan kemudian memperbarui isinya daripada menghapus dan membuat yang baru - yang akan dibuat di akhir heap) ini akan menjadi tersebar di seluruh heap, sehingga membutuhkan beberapa memori hit untuk membacanya semuanya ke dalam cache CPU. Aplikasi AC / C ++ kemungkinan besar akan mengalokasikan memori untuk elemen-elemen ini dan kemudian Anda memperbarui blok dengan data. (ok, ada struktur data seperti daftar yang berperilaku lebih seperti alokasi memori GC, tetapi orang tahu ini lebih lambat daripada vektor).
Anda dapat melihat ini beroperasi hanya dengan mengganti objek StringBuilder dengan String ... Stringbuilders bekerja dengan mengalokasikan memori dan mengisinya, dan merupakan trik kinerja yang dikenal untuk sistem java / .NET.
Jangan lupa bahwa paradigma 'hapus lama dan alokasikan salinan baru' sangat banyak digunakan di Java / C #, hanya karena orang diberitahu bahwa alokasi memori sangat cepat karena GC, dan model memori yang tersebar digunakan di mana-mana ( kecuali untuk pembuat string, tentu saja) jadi semua perpustakaan Anda cenderung boros memori dan menggunakan banyak, tidak ada yang mendapat manfaat dari persentuhan. Salahkan hype di sekitar GC untuk ini - mereka bilang memori gratis, lol.
GC itu sendiri jelas merupakan hit perf lain - ketika dijalankan, tidak hanya harus menyapu tumpukan, tetapi juga harus membebaskan semua blok yang tidak digunakan, dan kemudian harus menjalankan finalis apa pun (meskipun ini harus dilakukan secara terpisah dengan kali berikutnya dengan aplikasi dihentikan) (Saya tidak tahu apakah itu masih hit perf, tapi semua dokumen yang saya baca katakan hanya menggunakan finalis jika benar-benar diperlukan) dan kemudian harus memindahkan blok-blok ke posisi sehingga tumpukan adalah dipadatkan, dan perbarui referensi ke lokasi baru blok. Seperti yang Anda lihat, ini banyak pekerjaan!
Perf hit untuk memori C ++ turun ke alokasi memori - ketika Anda membutuhkan blok baru, Anda harus berjalan mencari tumpukan ruang kosong berikutnya yang cukup besar, dengan tumpukan sangat terfragmentasi, ini tidak hampir secepat GC 'hanya mengalokasikan blok lain di akhir' tapi saya pikir itu tidak selambat semua pekerjaan yang dilakukan pemadatan GC, dan dapat dikurangi dengan menggunakan beberapa tumpukan blok ukuran tetap (atau dikenal sebagai kumpulan memori).
Masih ada lagi ... seperti memuat rakitan dari GAC yang memerlukan pemeriksaan keamanan, jalur pemeriksaan (nyalakan sxstrace dan lihat saja apa yang sedang terjadi!) Dan rekayasa umum lainnya yang tampaknya jauh lebih populer dengan java / .net dari C / C ++.
sumber
"Apakah itu hanya karena C ++ dikompilasi ke kode assembly / mesin sedangkan Java / C # masih memiliki overhead pemrosesan kompilasi JIT saat runtime?" Pada dasarnya ya!
Catatan singkat, Java memiliki overhead lebih dari sekedar kompilasi JIT. Sebagai contoh, ia melakukan lebih banyak pengecekan untuk Anda (seperti itulah ia melakukan hal-hal seperti
ArrayIndexOutOfBoundsExceptions
danNullPointerExceptions
). Pengumpul sampah adalah overhead penting lainnya.Ada perbandingan yang cukup rinci di sini .
sumber
Ingatlah bahwa yang berikut ini hanya membandingkan perbedaan antara kompilasi asli dan JIT, dan tidak mencakup spesifikasi bahasa atau kerangka kerja tertentu. Mungkin ada alasan yang sah untuk memilih platform tertentu di luar ini.
Ketika kami mengklaim bahwa kode asli lebih cepat, kita berbicara tentang kasus penggunaan khas dari kode yang dikompilasi secara native versus kode yang dikompilasi JIT, di mana penggunaan khas dari aplikasi yang dikompilasi JIT akan dijalankan oleh pengguna, dengan hasil langsung (misalnya, tidak ada tunggu dulu kompiler). Dalam hal ini, saya tidak berpikir siapa pun dapat mengklaim dengan wajah lurus, bahwa kode yang dikompilasi JIT dapat cocok atau mengalahkan kode asli.
Mari kita asumsikan kita memiliki program yang ditulis dalam beberapa bahasa X, dan kita dapat mengkompilasinya dengan kompiler asli, dan lagi dengan kompiler JIT. Setiap alur kerja memiliki tahapan yang sama, yang dapat digeneralisasi sebagai (Kode -> Representasi Menengah -> Kode Mesin -> Eksekusi). Perbedaan besar antara dua adalah tahapan mana yang dilihat oleh pengguna dan mana yang dilihat oleh programmer. Dengan kompilasi asli, programmer melihat semua kecuali tahap eksekusi, tetapi dengan solusi JIT, kompilasi ke kode mesin dilihat oleh pengguna, di samping eksekusi.
Klaim bahwa A lebih cepat dari B mengacu pada waktu yang dibutuhkan untuk menjalankan program, seperti yang terlihat oleh pengguna . Jika kita mengasumsikan bahwa kedua keping kode bekerja secara identik dalam tahap Eksekusi, kita harus mengasumsikan bahwa alur kerja JIT lebih lambat untuk pengguna, karena ia juga harus melihat waktu T dari kompilasi ke kode mesin, di mana T> 0. Jadi , untuk setiap kemungkinan alur kerja JIT untuk melakukan hal yang sama seperti alur kerja asli, kepada pengguna, kita harus mengurangi waktu Eksekusi kode, sehingga Eksekusi + Kompilasi ke kode mesin, lebih rendah daripada hanya tahap Eksekusi dari alur kerja asli. Ini berarti kita harus mengoptimalkan kode lebih baik dalam kompilasi JIT daripada dalam kompilasi asli.
Namun, ini agak tidak layak, karena untuk melakukan optimasi yang diperlukan untuk mempercepat Eksekusi, kita harus menghabiskan lebih banyak waktu dalam mengkompilasi ke tahap kode mesin, dan dengan demikian, setiap kali kita menyimpan karena kode yang dioptimalkan benar-benar hilang, karena kami menambahkannya ke kompilasi. Dengan kata lain, "kelambatan" dari solusi berbasis JIT bukan hanya karena waktu tambahan untuk kompilasi JIT, tetapi kode yang dihasilkan oleh kompilasi tersebut bekerja lebih lambat daripada solusi asli.
Saya akan menggunakan contoh: Daftar alokasi. Karena akses memori beberapa ribu kali lebih lambat daripada akses register, idealnya kami ingin menggunakan register sedapat mungkin dan memiliki akses memori sesedikit mungkin, tetapi kami memiliki jumlah register yang terbatas, dan kami harus menumpahkan keadaan ke dalam memori ketika kami membutuhkan sebuah register. Jika kita menggunakan algoritma alokasi register yang membutuhkan 200ms untuk menghitung, dan sebagai hasilnya kita menghemat waktu eksekusi 2ms - kita tidak memanfaatkan waktu terbaik untuk kompiler JIT. Solusi seperti algoritma Chaitin, yang dapat menghasilkan kode yang sangat optimal tidak cocok.
Peran kompiler JIT adalah untuk mencapai keseimbangan terbaik antara waktu kompilasi dan kualitas kode yang dihasilkan, namun, dengan bias besar pada waktu kompilasi yang cepat, karena Anda tidak ingin membiarkan pengguna menunggu. Kinerja kode yang dieksekusi lebih lambat dalam kasus JIT, karena kompiler asli tidak terikat (banyak) berdasarkan waktu dalam mengoptimalkan kode, jadi bebas menggunakan algoritma terbaik. Kemungkinan keseluruhan kompilasi + eksekusi untuk kompiler JIT hanya dapat mengalahkan waktu eksekusi untuk kode yang dikompilasi secara asli adalah 0
Tetapi VM kami tidak hanya terbatas pada kompilasi JIT. Mereka menggunakan teknik kompilasi sebelumnya, caching, hot swapping, dan optimisasi adaptif. Jadi mari kita modifikasi klaim kami bahwa kinerja adalah apa yang dilihat pengguna, dan batasi sampai waktu yang diperlukan untuk pelaksanaan program (anggap kami telah mengkompilasi AOT). Kita dapat secara efektif membuat kode eksekusi setara dengan kompiler asli (atau mungkin lebih baik?). Klaim besar untuk VM adalah bahwa mereka mungkin dapat menghasilkan kode kualitas yang lebih baik daripada kompiler asli, karena ia memiliki akses ke lebih banyak informasi - bahwa dari proses yang berjalan, seperti seberapa sering fungsi tertentu dapat dieksekusi. VM kemudian dapat menerapkan optimasi adaptif ke kode yang paling penting melalui hot swapping.
Ada masalah dengan argumen ini - ia mengasumsikan bahwa optimasi yang dipandu profil dan sejenisnya adalah sesuatu yang unik untuk VM, yang tidak benar. Kita juga dapat menerapkannya pada kompilasi asli - dengan mengkompilasi aplikasi kita dengan profiling diaktifkan, merekam informasi, dan kemudian mengkompilasi ulang aplikasi dengan profil itu. Mungkin juga patut menunjukkan bahwa hot swapping kode bukanlah sesuatu yang hanya dapat dilakukan oleh kompiler JIT, kita dapat melakukannya untuk kode asli - meskipun solusi berbasis JIT untuk melakukan ini lebih mudah tersedia, dan jauh lebih mudah bagi pengembang. Jadi pertanyaan besarnya adalah: Dapatkah seorang VM menawarkan kami beberapa informasi yang tidak dapat dikompilasi oleh native, yang dapat meningkatkan kinerja kode kami?
Saya tidak bisa melihatnya sendiri. Kami dapat menerapkan sebagian besar teknik VM khas untuk kode asli juga - meskipun prosesnya lebih terlibat. Demikian pula, kita dapat menerapkan optimasi apa pun dari kompiler asli kembali ke VM yang menggunakan kompilasi AOT atau optimisasi adaptif. Kenyataannya adalah bahwa perbedaan antara kode asli yang dijalankan, dan yang dijalankan dalam VM tidak sebesar yang kami yakini. Mereka pada akhirnya mengarah pada hasil yang sama, tetapi mereka mengambil pendekatan yang berbeda untuk sampai ke sana. VM menggunakan pendekatan berulang untuk menghasilkan kode yang dioptimalkan, di mana kompiler asli mengharapkannya dari awal (dan dapat ditingkatkan dengan pendekatan berulang).
Seorang programmer C ++ mungkin berpendapat bahwa ia membutuhkan optimisasi sejak awal, dan seharusnya tidak menunggu seorang VM untuk mengetahui bagaimana melakukannya, jika memang ada. Ini mungkin titik yang valid dengan teknologi kami saat ini, karena tingkat optimisasi saat ini di VM kami lebih rendah daripada yang ditawarkan kompiler asli - tetapi itu tidak selalu menjadi masalah jika solusi AOT di VM kami meningkat, dll.
sumber
Artikel ini adalah ringkasan dari serangkaian posting blog yang mencoba membandingkan kecepatan c ++ vs c # dan masalah yang harus Anda atasi dalam kedua bahasa untuk mendapatkan kode kinerja tinggi. Rangkumannya adalah 'masalah perpustakaan Anda lebih dari apa pun, tetapi jika Anda menggunakan c ++ Anda dapat mengatasinya.' atau 'bahasa modern memiliki perpustakaan yang lebih baik dan karenanya mendapatkan hasil yang lebih cepat dengan upaya yang lebih rendah' tergantung pada kecenderungan filosofis Anda.
sumber
Saya pikir pertanyaan sebenarnya di sini bukanlah "mana yang lebih cepat?" tetapi "yang memiliki potensi terbaik untuk kinerja yang lebih tinggi?". Dilihat dari persyaratan tersebut, C ++ jelas menang - itu dikompilasi ke kode asli, tidak ada JITting, ini adalah abstraksi level yang lebih rendah, dll.
Itu jauh dari cerita lengkapnya.
Karena C ++ dikompilasi, setiap optimisasi kompiler harus dilakukan pada waktu kompilasi, dan optimisasi kompiler yang sesuai untuk satu mesin mungkin sepenuhnya salah untuk yang lain. Ini juga merupakan kasus bahwa setiap optimisasi kompiler global dapat dan akan lebih menyukai algoritma atau pola kode tertentu daripada yang lain.
Di sisi lain, program JITted akan mengoptimalkan pada waktu JIT, sehingga dapat menarik beberapa trik bahwa program yang dikompilasi tidak dapat dan dapat membuat optimasi yang sangat spesifik untuk mesin yang benar-benar berjalan dan kode yang sebenarnya dijalankan. Setelah Anda melewati overhead awal JIT, dalam beberapa kasus berpotensi untuk lebih cepat.
Dalam kedua kasus implementasi yang masuk akal dari algoritma dan contoh lain dari programmer yang tidak bodoh kemungkinan akan menjadi faktor yang jauh lebih signifikan, namun - misalnya, sangat mungkin untuk menulis kode string yang benar-benar mati otak dalam C ++ yang akan ditempa oleh bahkan bahasa scripting yang ditafsirkan.
sumber
-march=native
). - "ini level abstraksi yang lebih rendah" tidak sepenuhnya benar. C ++ menggunakan abstraksi tingkat tinggi seperti halnya Java (atau, pada kenyataannya, abstraksi yang lebih tinggi: pemrograman fungsional? Templat metaprogramming?), Ia hanya mengimplementasikan abstraksi yang kurang "bersih" daripada Java.Kompilasi JIT sebenarnya memiliki dampak negatif pada kinerja. Jika Anda mendesain kompiler "sempurna" dan kompiler JIT "sempurna", opsi pertama akan selalu menang dalam kinerja.
Baik Java dan C # ditafsirkan ke dalam bahasa perantara, dan kemudian dikompilasi ke kode asli saat runtime, yang mengurangi kinerja.
Tapi sekarang perbedaannya tidak begitu jelas untuk C #: Microsoft CLR menghasilkan kode asli yang berbeda untuk CPU yang berbeda, sehingga membuat kode lebih efisien untuk mesin yang sedang berjalan, yang tidak selalu dilakukan oleh kompiler C ++.
PS C # ditulis dengan sangat efisien dan tidak memiliki banyak lapisan abstraksi. Ini tidak benar untuk Java, yang tidak efisien. Jadi, dalam hal ini, dengan CLR greate-nya, program C # sering menunjukkan kinerja yang lebih baik daripada program C ++. Untuk selengkapnya tentang .Net dan CLR, lihat "CLR via C #" karya Jeffrey Richter .
sumber