C ++ başlangıç ​​tahsisi neden C'lerden çok daha büyük?


138

Aynı kodu kullanırken, derleyiciyi (C derleyicisinden C ++ derleyicisine) değiştirmek, ne kadar bellek ayrılacağını değiştirir. Bunun neden olduğundan emin değilim ve daha fazla anlamak istiyorum. Şimdiye kadar aldığım en iyi yanıt "muhtemelen I / O akışları", bu çok açıklayıcı değil ve bana C ++ "kullanmadığınız için ödeme yapmaz" yönü hakkında merak ediyor.

Sırasıyla 7.0.1-8 ve 8.3.0-6 sürümleri olan Clang ve GCC derleyicilerini kullanıyorum. Sistemim en son Debian 10 (Buster) üzerinde çalışıyor. Kıyaslamalar Valgrind Massif aracılığıyla yapılır.

#include <stdio.h>

int main() {
    printf("Hello, world!\n");
    return 0;
}

Kullanılan kod değişmez, ancak C ya da C ++ olarak derlesem Valgrind karşılaştırmasının sonuçlarını değiştirir. Ancak değerler derleyiciler arasında tutarlı kalır. Program için çalışma zamanı ayırmaları (tepe noktası) aşağıdaki gibidir:

  • GCC (C): 1.032 bayt (1 KB)
  • G ++ (C ++): 73,744 bayt, (~ 74 KB)
  • Clang (C): 1.032 bayt (1 KB)
  • Clang ++ (C ++): 73,744 bayt (~ 74 KB)

Derleme için aşağıdaki komutları kullanıyorum:

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

Valgrind için, valgrind --tool=massif --massif-out-file=m_compiler_lang ./compiler-langher derleyici ve dilde, sonra ms_printzirveleri görüntülemek için çalışıyorum.

Burada yanlış bir şey mi yapıyorum?


11
Başlangıç ​​olarak, nasıl inşa ediyorsunuz? Hangi seçenekleri kullanıyorsunuz? Ve nasıl ölçüyorsun? Valgrind'i nasıl çalıştırıyorsunuz?
Bazı programcı ahbap

17
Doğru hatırlıyorsam, modern C ++ derleyicileri try, belki de bir atlama tablosu veya başka bir şeyle, daha büyük bir bellek ayak izi pahasına bir bloğa girmenin performansının olmadığı bir istisna modeline sahip olmalıdır . İstisnasız derlemeyi deneyin ve bunun nasıl bir etkisi olduğunu görün. Düzenleme: Aslında, iteratif olarak bellek ayak izi üzerinde ne etkisi görmek için çeşitli c ++ özellikleri devre dışı bırakmayı deneyin.
François Andrieux

3
clang++ -xcBunun yerine derlerken clang, aynı tahsisat oradaydı, bu da bağlantılı kütüphaneler nedeniyle olduğunu şiddetle tavsiye ediyor
Justin

14
@bigwillydos Bu gerçekten C ++, kırdığı C ++ özelliklerinin herhangi bir bölümünü görmüyorum ... Potansiyel olarak cstdio yerine stdio.h dahil olmakla birlikte, bu en azından eski C ++ sürümünde izin verilir. Sizce bu programda "hatalı biçimlendirilmiş" nedir?
Vality

4
Bu gcc ve clang derleyicilerinin Cmodda tam olarak aynı sayıda bayt ve aynı sayıda bayt C++modunda oluşturduğundan şüpheleniyorum . Bir transkripsiyon hatası mı yaptınız?
RonJohn

Yanıtlar:


149

Yığın kullanımı C ++ standart kitaplığından gelir. Başlangıçta dahili kütüphane kullanımı için bellek ayırır. Buna karşı bağlantı oluşturmazsanız, C ve C ++ sürümü arasında sıfır fark olmalıdır. GCC ve Clang ile dosyayı aşağıdakilerle derleyebilirsiniz:

g ++ -Wl, - gerektiği gibi main.cpp

Bu, bağlayıcıya kullanılmayan kütüphanelere bağlantı vermemesi talimatını verecektir. Örnek kodunuzda, C ++ kitaplığı kullanılmadığından, C ++ standart kitaplığına bağlanmamalıdır.

Bunu C dosyasıyla da test edebilirsiniz. Şunlarla derlerseniz:

gcc main.c -lstdc ++

Bir C programı oluşturmuş olsanız bile yığın kullanımı yeniden görünecektir.

Öbek kullanımı, kullandığınız belirli C ++ kitaplığı uygulamasına açıktır. Sizin durumunuzda, bu GNU C ++ kütüphanesi, libstdc ++ . Diğer uygulamalar aynı miktarda bellek ayırmayabilir veya hiç bellek ayırmayabilir (en azından başlangıçta değil.) Örneğin LLVM C ++ kitaplığı ( libc ++ ) başlangıçta en azından Linux'umda yığın ayırma yapmaz makine:

clang ++ -stdlib = libc ++ main.cpp

Yığın kullanımı, ona hiç bağlanma ile aynıdır.

(Derleme başarısız olursa, libc ++ muhtemelen yüklü değildir. Paket adı genellikle "libc ++" veya "libcxx" içerir.)


50
Bu yanıtı gördüğümde, ilk düşüncem " Bu bayrak gereksiz yükü azaltmaya yardımcı oluyorsa, neden varsayılan olarak açık değil " dir. Buna iyi bir cevap var mı?
Nat

4
@Nat Benim tahminim dev zamanda derlemek için yavaş olduğunu. Bir sürüm derlemesi oluşturmaya hazır olduğunuzda onu açarsınız. Ayrıca normal / büyük bir kod tabanında fark çok az olabilir (eğer çok sayıda STD kütüphanesi kullanıyorsanız)
DarcyThomas

24
@Nat -Wl,--as-neededBayrak, -lbayraklarınızda belirttiğiniz ancak aslında kullanmadığınız kitaplıkları kaldırır . Eğer bir kütüphane kullanmıyorsanız, o zaman ona karşı bağlantı vermeyin. Bunun için bu bayrağa ihtiyacınız yok. Ancak, derleme sisteminiz çok fazla kütüphane eklerse ve hepsini temizlemek ve yalnızca gerekli olanları bağlamak çok fazla iş gerektiriyorsa, bunun yerine bu bayrağı kullanabilirsiniz. Standart kitaplık, otomatik olarak bağlandığı için bir istisnadır. Yani bu bir köşe davası.
Nikos

36
@Nat - gerektiği gibi istenmeyen yan etkilere sahip olabilir, bir kütüphanenin herhangi bir sembolünü kullanıp kullanmadığınızı kontrol ederek çalışır ve testi geçemeyenleri başlatır. AMA: Bir kütüphane de çeşitli şeyler üstü kapalı yapabilir, örneğin kütüphanede statik bir C ++ örneğiniz varsa yapıcısı otomatik olarak çağrılır. Açıkça çağırmadığınız bir kütüphanenin gerekli olduğu nadir durumlar vardır, ancak bunlar vardır.
Norbert Lange

3
@NikosC. Buildsystems, uygulamanızın hangi sembolleri kullandığını ve bunları hangi kitaplıkların uyguladığını otomatik olarak bilmez (derleyiciler, archs, distros ve c / c ++ kitaplıkları arasında değişir). Bunu doğru yapmak oldukça zahmetli, en azından temel çalışma zamanı kütüphaneleri için. Ancak nadir durumlarda bir kütüphaneye ihtiyacınız var, bunun için gerekli olanı kullanmamalı ve başka her yerde gerektiği gibi bırakmalısınız. Gördüğüm bir usecase, izleme / hata ayıklama (lttng) kütüphaneleri ve kimlik doğrulama / bağlanma gibi şeyler yapan kütüphaneler.
Norbert Lange

16

Ne GCC ne de Clang derleyici değildir - aslında araç zinciri sürücü programlarıdır. Bu derleyici, montajcı ve bağlayıcı çağırır anlamına gelir.

Kodunuzu bir C veya C ++ derleyicisi ile derlerseniz, aynı derleme üretilir. Assembler aynı nesneleri üretecektir. Fark, araç zinciri sürücüsünün iki farklı dil için bağlayıcıya farklı girdiler sağlamasıdır: farklı başlangıçlar (C ++, ad alanı düzeyinde statik veya iş parçacığı yerel depolama süresine sahip nesneler için yapıcıları ve yıkıcıları çalıştırmak için kod gerektirir ve yığın için altyapı gerektirir örneğin, istisna işleme sırasında gevşemeyi destekleyen çerçeveler), C ++ standart kitaplığı (ad alanı düzeyinde statik depolama süresine sahip nesneler de içerir) ve muhtemelen ek çalışma zamanı kitaplıkları (örneğin, yığın çözme altyapısıyla libgcc).

Kısacası, ayak izindeki artışa neden olan derleyici değil, C ++ dilini seçerek kullanmayı seçtiğiniz şeylerin bağlantısı.

C ++ 'ın "yalnızca kullandığınız kadar ödeyin" felsefesine sahip olduğu doğrudur, ancak dili kullanarak ödersiniz. Dilin bölümlerini (RTTI, özel durum işleme) devre dışı bırakabilirsiniz, ancak artık C ++ kullanmıyorsunuz. Başka bir cevapta belirtildiği gibi, standart kütüphaneyi hiç kullanmazsanız, sürücüye bunu dışarıda bırakma talimatı verebilirsiniz (--Wl, - gerektiği gibi), ancak herhangi bir özelliği kullanmayacaksanız C ++ veya kütüphanesinin neden bir programlama dili olarak C ++ 'ı seçiyorsunuz?


İstisna işlemeyi etkinleştirmenin, aslında kullanmasanız bile bir maliyeti olması bir sorundur. Bu genel olarak C ++ özellikleri için normal değildir ve C ++ standartları çalışma gruplarının düzeltmenin yollarını düşünmeye çalıştığı bir şeydir. Herb Sutter'ın ACCU 2019 De-fragmenting C ++ ile yaptığı açılış konuşmasına bakın : İstisnaları daha uygun fiyatlı ve kullanılabilir hale getirin . Bununla birlikte, mevcut C ++ 'da talihsiz bir gerçektir. Ve bir anahtar kelimeyle yeni istisnalar için yeni mekanizmalar eklenmiş olsa bile, geleneksel C ++ istisnaları muhtemelen her zaman bu maliyete sahip olacaktır.
Peter Cordes
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.