Чому початкове виділення C ++ настільки більше, ніж C?


138

При використанні одного і того ж коду, просто зміна компілятора (з компілятора C на компілятор C ++) змінить кількість виділеної пам'яті. Я не зовсім впевнений, чому це так, і хотів би це зрозуміти більше. Поки найкраща відповідь, яку я отримав, - це "ймовірно, потоки вводу / виводу", що не є дуже описовим і змушує замислитися над аспектом "С ++", "ти не платиш за те, що не використовуєш".

Я використовую компілятори Clang та GCC, версії 7.0.1-8 та 8.3.0-6 відповідно. Моя система працює на Debian 10 (Buster), останнє. Орієнтири здійснюються за допомогою Valgrind Massif.

#include <stdio.h>

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

Використовуваний код не змінюється, але якщо я компілюю як C або як C ++, він змінює результати критерію Valgrind. Однак значення залишаються послідовними для компіляторів. Виділення (пік) для виконання програми тривають наступним чином:

  • GCC (C): 1032 байт (1 КБ)
  • G ++ (C ++): 73,744 байт, (~ 74 КБ)
  • Кланг (C): 1032 байт (1 КБ)
  • Clang ++ (C ++): 73,744 байт (~ 74 КБ)

Для компіляції я використовую такі команди:

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 я працюю valgrind --tool=massif --massif-out-file=m_compiler_lang ./compiler-langна кожному компіляторі та мові, а потім ms_printдля показу піків.

Чи я тут щось неправильно роблю?


11
Для початку, як ви будуєте? Які варіанти ви використовуєте? А як ви вимірюєте? Як ти ведеш Valgrind?
Якийсь програміст чувак

17
Якщо я добре пам’ятаю, сучасні компілятори C ++ мають модель винятку, коли не вдається досягти продуктивності для введення tryблоку за рахунок більшого сліду пам’яті, можливо, за допомогою таблиці стрибків чи чогось іншого. Можливо, спробуйте скласти без виключень і подивіться, який вплив це має. Редагувати: Насправді, повторно спробуйте відключити різні функції c ++, щоб побачити, який вплив має вплив на пам'ять.
Франсуа

3
При компілюванні clang++ -xcзамість clangтого ж виділення було таке, що настійно говорить про його завдяки пов’язаним бібліотекам
Джастін

14
@bigwillydos Це справді C ++, я не бачу жодної частини специфікацій C ++, яку він порушує ... Крім потенційного, включаючи stdio.h, а не cstdio, але це дозволено принаймні у старій версії C ++. Як ви думаєте, що в цій програмі "неправильно"?
Vality

4
Мені здається підозрілим те, що ці компілятори gcc та clang генерують точно таку ж кількість байтів у Cрежимі та точно таку ж кількість байтових C++режимів. Ви зробили помилку транскрипції?
РонДжон

Відповіді:


149

Використання купи відбувається з стандартної бібліотеки C ++. Він виділяє пам'ять для внутрішнього використання бібліотеки при запуску. Якщо ви не пов'язуєте проти нього, між версією C та C ++ має бути нульова різниця. За допомогою GCC та Clang ви можете компілювати файл із:

g ++ -Wl, - за потребою main.cpp

Це дасть вказівку лінкеру не зв’язуватися з невикористаними бібліотеками. У вашому прикладі коду бібліотека C ++ не використовується, тому вона не повинна посилатися на стандартну бібліотеку C ++.

Ви також можете перевірити це за допомогою файлу C. Якщо ви компілюєте з:

gcc main.c -lstdc ++

Використання купи знову з’явиться, навіть якщо ви створили програму C.

Використання купи очевидно залежить від конкретної реалізації бібліотеки C ++, яку ви використовуєте. У вашому випадку це бібліотека GNU C ++, libstdc ++ . Інші реалізації можуть не виділяти стільки ж пам’яті, або взагалі не можуть виділяти пам'ять (принаймні, не під час запуску.) Бібліотека LLVM C ++ ( libc ++ ), наприклад, не здійснює розподілу купи під час запуску, принаймні в моєму Linux машина:

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

Використання купи - це те саме, що зовсім не пов'язувати проти неї.

(Якщо компіляція не вдається, тоді libc ++, ймовірно, не встановлений. Ім'я пакета зазвичай містить "libc ++" або "libcxx".)


50
Побачивши цю відповідь, моя перша думка виглядає так: " Якщо цей прапор допомагає зменшити непотрібні накладні витрати, чому він не вмикається за замовчуванням? ". Чи є на це хороша відповідь?
Нат

4
@Nat Мої здогадки, що в розроблений час, це повільніше збирати. Коли ви будете готові створити збірку релізів, тоді ви б увімкнули її. Також у звичайній / великій кодовій базі різниця може бути мінімальною (якщо ви використовуєте безліч бібліотеки STD тощо)
DarcyThomas

24
@Nat -Wl,--as-neededПрапор видаляє бібліотеки, які ви вказали у своїх -lпрапорах, але ви насправді не використовуєте. Тож якщо ви не використовуєте бібліотеку, просто не посилайтеся на неї. Вам не потрібен цей прапор. Однак якщо ваша система збірки додає занадто багато бібліотек, і було б дуже багато роботи, щоб очистити їх усіх і зв’язати лише необхідне, тоді ви можете використовувати цей прапор замість цього. Стандартна бібліотека є винятком, оскільки вона автоматично пов'язана з. Тож це кутовий випадок.
Нікос К.

36
@Nat - потрібні можуть мати небажані побічні ефекти, він працює, перевіряючи, чи використовуєте ви який-небудь символ бібліотеки, і видаляє ті, які не виходять з тесту. АЛЕ: бібліотека також може робити різні речі неявно, наприклад, якщо у вас є статичний екземпляр C ++ у бібліотеці, то його конструктор буде автоматично викликаний. Є рідкісні випадки, коли потрібна бібліотека, до якої явно не звертаєтесь, але вони існують.
Норберт Ланге

3
@NikosC. Будівельні системи не знають автоматично, які символи використовує ваше додаток, і які бібліотеки їх реалізують (залежить від компіляторів, архівів, дистрибутивів і бібліотек c / c ++). Отримати це право досить клопітно, як мінімум для базових бібліотек виконання. Але для рідкісних випадків вам потрібна бібліотека, ви просто повинні використовувати - не потрібну для цього, а залишити - потрібну всюди. Я бачив те, що я бачив - це бібліотеки для відстеження / налагодження (lttng) та бібліотеки, які роблять щось подібне до автентифікації / з'єднання.
Норберт Ланге

16

Ні GCC, ні Clang не є компіляторами - вони фактично є програмами драйверів інструментальних ланцюгів. Це означає, що вони викликають компілятор, асемблер та лінкер.

Якщо ви компілюєте свій код за допомогою компілятора C або C ++, ви отримаєте таку ж збірку. Асемблер буде виробляти ті самі об'єкти. Різниця полягає в тому, що драйвер ланцюжка інструментів надасть різний вхід до лінкера для двох різних мов: різні стартапи (C ++ вимагає код для виконання конструкторів та деструкторів для об'єктів зі статичною тривалістю зберігання або потоком локального зберігання на рівні простору імен та потребує інфраструктури для стека кадри для підтримки розмотування під час обробки винятків, наприклад, стандартна бібліотека C ++ (яка також має об'єкти статичної тривалості зберігання на рівні простору імен) і, ймовірно, додаткові бібліотеки виконання (наприклад, libgcc зі своєю інфраструктурою розмотування стека).

Коротше кажучи, не компілятор спричиняє збільшення сліду, це зв’язування речей, які ви вирішили використовувати, обираючи мову C ++.

Це правда, що C ++ має філософію "платити лише за те, що ти використовуєш", але, використовуючи мову, ти платиш за неї. Ви можете відключити частини мови (RTTI, обробка винятків), але тоді ви більше не використовуєте C ++. Як було сказано в іншій відповіді, якщо ви взагалі не використовуєте стандартну бібліотеку, ви можете доручити драйверу залишити це (--Wl, - за потребою), але якщо ви не збираєтесь використовувати жодну з функцій C ++ або його бібліотеки, чому ви навіть вибираєте C ++ як мову програмування?


Факт, що ввімкнення обробки винятків коштує, навіть якщо ви його фактично не використовуєте, є проблемою. Це взагалі не нормально для функцій C ++ взагалі, і це те, що робочі групи зі стандартів C ++ намагаються придумати шляхи їх виправлення. Дивіться основну бесіду Herb Sutter на ACCU 2019 De-fragmenting C ++: Зробити винятки більш доступними та зручними . Це прикро, але в нинішньому C ++. І традиційні винятки C ++, ймовірно, завжди матимуть таку вартість, навіть якщо / коли нові ключові слова додаються нові механізми для нових винятків.
Пітер Кордес
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.