C ++ 초기 할당이 C보다 훨씬 큰 이유는 무엇입니까?


138

동일한 코드를 사용하는 경우 컴파일러를 C 컴파일러에서 C ++ 컴파일러로 변경하면 할당되는 메모리 양이 변경됩니다. 왜 이것이 더 많은지 잘 모르겠습니다. 지금까지 내가 얻은 최고의 응답은 "아마도 I / O 스트림"입니다. 이는 매우 설명 적이 지 않으며 C ++의 "사용하지 않는 것에 대해 비용을 지불하지 않습니다"에 대해 궁금해합니다.

Clang 및 GCC 컴파일러 버전 7.0.1-8 및 8.3.0-6을 각각 사용하고 있습니다. 내 시스템은 최신 데비안 10 (버스터)에서 실행되고 있습니다. 벤치 마크는 Valgrind Massif를 통해 이루어집니다.

#include <stdio.h>

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

사용 된 코드는 변경되지 않지만 C 또는 C ++로 컴파일하든 Valgrind 벤치 마크의 결과가 변경됩니다. 그러나 값은 컴파일러에서 일관성을 유지합니다. 프로그램의 런타임 할당 (피크)은 다음과 같습니다.

  • GCC (C) : 1,032 바이트 (1KB)
  • G ++ (C ++) : 73,744 바이트, (~ 74KB)
  • 클랑 (C) : 1,032 바이트 (1KB)
  • Clang ++ (C ++) : 73,744 바이트 (~ 74KB)

컴파일을 위해 다음 명령을 사용합니다.

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 ++ 기능을 비활성화하여 메모리 풋 프린트에 어떤 영향을 미치는지 확인하십시오.
François Andrieux

3
clang++ -xc대신에 컴파일 할 때 clang동일한 할당이 있었는데, 이는 연결된 라이브러리로 인한 것이 좋습니다
Justin

14
@bigwillydos 이것은 실제로 C ++이며, C ++ 사양의 어떤 부분도 깨지지 않습니다 ... cstdio 대신 stdio.h를 잠재적으로 포함 시키지는 않지만 적어도 이전 C ++ 버전에서는 허용됩니다. 이 프로그램에서 "잘못된"것이 무엇이라고 생각하십니까?
Vality

4
해당 gcc 및 clang 컴파일러가 C모드에서 정확히 동일한 바이트 수와 정확히 동일한 바이트 수 모드를 생성하는 것으로 의심 C++됩니다. 전사 오류가 발생 했습니까?
RonJohn

답변:


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
이 답변을 볼 때, 나의 첫 생각은 " 이 플래그가 불필요한 오버 헤드를 줄이는 데 도움이된다면 왜 기본적으로 켜져 있지 않습니까? "입니다. 그것에 대한 좋은 대답이 있습니까?
Nat

4
@Nat 내 추측은 dev 시간에 컴파일 속도가 느립니다. 릴리스 빌드를 작성할 준비가되면 켜십시오. 또한 표준 / 대규모 코드베이스에서는 차이가 최소화 될 수 있습니다 (STD 라이브러리 등을 많이 사용하는 경우)
DarcyThomas

24
@Nat -Wl,--as-needed플래그는 플래그에 지정한 라이브러리를 제거 -l하지만 실제로 사용하지는 않습니다. 따라서 라이브러리를 사용하지 않으면 링크하지 마십시오. 이를 위해이 플래그가 필요하지 않습니다. 그러나 빌드 시스템이 너무 많은 라이브러리를 추가하고 라이브러리를 모두 정리하고 필요한 라이브러리 만 링크하는 데 많은 작업이 필요한 경우이 플래그를 대신 사용할 수 있습니다. 표준 라이브러리는 자동으로 연결되므로 예외입니다. 이것은 코너 케이스입니다.
Nikos C.

36
@Nat-필요에 따라 원치 않는 부작용이 발생할 수 있습니다. 라이브러리의 기호를 사용하는지 여부를 확인하고 테스트에 실패한 사람들을 쫓아냅니다. 그러나 라이브러리는 또한 암묵적으로 다양한 작업을 수행 할 수 있습니다. 예를 들어 라이브러리에 정적 C ++ 인스턴스가 있으면 생성자가 자동으로 호출됩니다. 명시 적으로 호출하지 않는 라이브러리가 필요한 경우는 드물지만 존재합니다.
Norbert Lange

3
@ 니코 빌드 시스템은 애플리케이션이 사용하는 심볼과이를 구현하는 라이브러리를 자동으로 알지 못합니다 (컴파일러, 아치, 배포판 및 c / c ++ 라이브러리에 따라 다름). 기본 런타임 라이브러리에는이 문제를 해결하는 것이 다소 번거 롭습니다. 그러나 드문 경우이지만 라이브러리가 필요하면 해당 라이브러리에 필요하지 않고 다른 곳에서는 필요에 따라 두어야합니다. 내가 본 유스 케이스는 추적 / 디버깅 (lttng) 용 라이브러리와 일종의 인증 / 연결을 수행하는 라이브러리입니다.
Norbert Lange

16

GCC 나 Clang은 모두 컴파일러가 아니며 실제로 툴체인 드라이버 프로그램입니다. 즉, 컴파일러, 어셈블러 및 링커를 호출합니다.

C 또는 C ++ 컴파일러로 코드를 컴파일하면 동일한 어셈블리가 생성됩니다. 어셈블러는 동일한 객체를 생성합니다. 차이점은 툴체인 드라이버가 서로 다른 두 가지 언어에 대해 링커에 다른 입력을 제공한다는 것입니다. 다른 시작 (C ++은 네임 스페이스 수준에서 정적 또는 스레드 로컬 스토리지 기간이있는 객체의 생성자와 소멸자를 실행하기위한 코드가 필요하며 스택을위한 인프라가 필요합니다) 예를 들어 예외 처리 중 해제를 지원하는 프레임, C ++ 표준 라이브러리 (네임 스페이스 레벨에서 정적 스토리지 기간의 오브젝트도 포함) 및 추가 런타임 라이브러리 (예 : 스택 해제 인프라가있는 libgcc).

요컨대, 풋 프린트를 증가시키는 컴파일러는 아니며 C ++ 언어를 선택하여 사용하기로 선택한 것들을 연결합니다.

C ++에 "사용하는만큼만 지불"이라는 철학이 있지만, 언어를 사용하면 비용을 지불하는 것이 사실입니다. 언어의 일부 (RTTI, 예외 처리)를 비활성화 할 수 있지만 더 이상 C ++을 사용하지 않습니다. 다른 답변에서 언급했듯이 표준 라이브러리를 전혀 사용하지 않으면 드라이버가 필요하지 않게 (--Wl,-필요한 경우) 드라이버를 지시 할 수 있지만 기능을 사용하지 않을 경우 C ++ 또는 라이브러리에서 왜 C ++을 프로그래밍 언어로 선택합니까?


실제로 사용하지 않더라도 예외 처리를 활성화하는 데 비용이 발생한다는 사실은 문제입니다. 일반적으로 C ++ 기능에는 정상적이지 않으며 C ++ 표준 작업 그룹이 해결 방법을 생각하고 있습니다. ACCU 2019 Defragmenting C ++ : 예외를보다 저렴하고 유용하게 만들기 에서 Herb Sutter의 기조 연설을 참조하십시오 . 그러나 현재 C ++에서는 불행한 사실입니다. 그리고 새로운 예외에 대한 새로운 메커니즘이 키워드와 함께 추가되는 경우에도 전통적인 C ++ 예외는 항상 그 비용을 부담하게됩니다.
Peter Cordes 2016 년
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.