Saat menggunakan kode yang sama, mengubah kompiler (dari kompilator C ke kompilator C ++) akan mengubah berapa banyak memori yang dialokasikan. Saya tidak begitu yakin mengapa ini terjadi dan ingin lebih memahaminya. Sejauh ini tanggapan terbaik yang saya dapatkan adalah "mungkin aliran I / O", yang tidak terlalu deskriptif dan membuat saya bertanya-tanya tentang aspek "Anda tidak membayar untuk apa yang tidak Anda gunakan" dari C ++.
Saya menggunakan kompiler Clang dan GCC, masing-masing versi 7.0.1-8 dan 8.3.0-6. Sistem saya berjalan di Debian 10 (Buster), terbaru. Tolok ukur dilakukan melalui Valgrind Massif.
#include <stdio.h>
int main() {
printf("Hello, world!\n");
return 0;
}
Kode yang digunakan tidak berubah, tetapi apakah saya mengkompilasi sebagai C atau sebagai C ++, itu mengubah hasil benchmark Valgrind. Namun, nilainya tetap konsisten di seluruh penyusun. Alokasi runtime (puncak) untuk program berjalan sebagai berikut:
- GCC (C): 1.032 byte (1 KB)
- G ++ (C ++): 73.744 byte, (~ 74 KB)
- Dentang (C): 1.032 byte (1 KB)
- Clang ++ (C ++): 73.744 byte (~ 74 KB)
Untuk kompilasi, saya menggunakan perintah berikut:
clang -O3 -o c-clang ./main.c
gcc -O3 -o c-gcc ./main.c
clang++ -O3 -o cpp-clang ./main.cpp
g++ -O3 -o cpp-gcc ./main.cpp
Untuk Valgrind, saya menjalankan valgrind --tool=massif --massif-out-file=m_compiler_lang ./compiler-lang
setiap compiler dan bahasa, lalu ms_print
untuk menampilkan puncaknya.
Apakah saya melakukan sesuatu yang salah di sini?
sumber
try
blok dengan mengorbankan jejak memori yang lebih besar, mungkin dengan tabel lompat atau sesuatu. Mungkin coba kompilasi tanpa pengecualian dan lihat apa dampaknya. Sunting: Nyatanya, coba nonaktifkan berbagai fitur c ++ secara berulang untuk melihat dampaknya pada footprint memori.clang++ -xc
alih - alihclang
, alokasi yang sama ada di sana, yang sangat menyarankan itu karena perpustakaan tertautC
mode dan jumlahC++
mode byte yang sama persis . Apakah Anda membuat kesalahan transkripsi?Jawaban:
Penggunaan heap berasal dari pustaka standar C ++. Ini mengalokasikan memori untuk penggunaan perpustakaan internal saat startup. Jika Anda tidak menautkannya, seharusnya tidak ada perbedaan antara versi C dan C ++. Dengan GCC dan Clang, Anda dapat mengompilasi file dengan:
Ini akan menginstruksikan penaut untuk tidak menautkan ke pustaka yang tidak digunakan. Dalam kode contoh Anda, pustaka C ++ tidak digunakan, jadi seharusnya tidak ditautkan ke pustaka standar C ++.
Anda juga dapat menguji ini dengan file C. Jika Anda mengkompilasi dengan:
Penggunaan heap akan muncul kembali, meskipun Anda telah membuat program C.
Penggunaan heap jelas bergantung pada implementasi library C ++ spesifik yang Anda gunakan. Dalam kasus Anda, itulah pustaka GNU C ++, libstdc ++ . Implementasi lain mungkin tidak mengalokasikan jumlah memori yang sama, atau mereka mungkin tidak mengalokasikan memori sama sekali (setidaknya tidak saat startup.) Perpustakaan LLVM C ++ ( libc ++ ) misalnya tidak melakukan alokasi heap saat startup, setidaknya di Linux saya mesin:
Penggunaan heap sama dengan tidak menautkan sama sekali.
(Jika kompilasi gagal, libc ++ mungkin tidak diinstal. Nama paket biasanya berisi "libc ++" atau "libcxx".)
sumber
-Wl,--as-needed
Bendera menghapus pustaka yang Anda tentukan di-l
bendera Anda tetapi sebenarnya tidak Anda gunakan. Jadi jika Anda tidak menggunakan perpustakaan, jangan tautkan ke perpustakaan itu. Anda tidak membutuhkan bendera ini untuk ini. Namun, jika sistem build Anda menambahkan terlalu banyak pustaka dan akan merepotkan untuk membersihkan semuanya dan hanya menautkan yang diperlukan, Anda dapat menggunakan tanda ini sebagai gantinya. Pustaka standar adalah pengecualian, karena itu secara otomatis ditautkan. Jadi ini adalah kasus sudut.Baik GCC maupun Clang bukanlah kompiler - mereka sebenarnya adalah program driver toolchain. Itu berarti mereka memanggil compiler, assembler, dan linker.
Jika Anda mengkompilasi kode Anda dengan kompiler C atau C ++, Anda akan mendapatkan perakitan yang sama. Assembler akan menghasilkan objek yang sama. Perbedaannya adalah driver toolchain akan memberikan masukan yang berbeda ke linker untuk dua bahasa yang berbeda: startup yang berbeda (C ++ memerlukan kode untuk mengeksekusi konstruktor dan destruktor untuk objek dengan durasi penyimpanan statis atau thread-lokal pada tingkat namespace, dan memerlukan infrastruktur untuk stack frame untuk mendukung pelepasan selama pemrosesan pengecualian, misalnya), pustaka standar C ++ (yang juga memiliki objek dengan durasi penyimpanan statis pada tingkat ruang nama), dan mungkin pustaka waktu proses tambahan (misalnya, libgcc dengan infrastruktur pelepasan tumpukannya).
Singkatnya, ini bukan kompiler yang menyebabkan peningkatan footprint, ini adalah penautan hal-hal yang Anda pilih untuk digunakan dengan memilih bahasa C ++.
Memang benar bahwa C ++ memiliki filosofi "bayar hanya untuk apa yang Anda gunakan", tetapi dengan menggunakan bahasanya, Anda membayarnya. Anda dapat menonaktifkan bagian bahasa (RTTI, penanganan pengecualian) tetapi kemudian Anda tidak menggunakan C ++ lagi. Seperti yang disebutkan dalam jawaban lain, jika Anda tidak menggunakan pustaka standar sama sekali, Anda dapat menginstruksikan pengemudi untuk membiarkannya (--Wl, - sesuai kebutuhan) tetapi jika Anda tidak akan menggunakan fitur apa pun C ++ atau librarynya, mengapa Anda memilih C ++ sebagai bahasa pemrograman?
sumber