Ao usar o mesmo código, simplesmente alterar o compilador (de um compilador C para um compilador C ++) alterará a quantidade de memória alocada. Não tenho muita certeza do porquê disso e gostaria de entender mais. Até agora, a melhor resposta que recebi é "provavelmente os fluxos de E / S", o que não é muito descritivo e me faz pensar sobre o aspecto do C ++ como "você não paga pelo que não usa".
Estou usando os compiladores Clang e GCC, versões 7.0.1-8 e 8.3.0-6, respectivamente. Meu sistema está sendo executado no Debian 10 (Buster), mais recente. Os benchmarks são feitos via Valgrind Massif.
#include <stdio.h>
int main() {
printf("Hello, world!\n");
return 0;
}
O código usado não muda, mas, se eu compilar como C ou C ++, ele altera os resultados do benchmark Valgrind. Os valores permanecem consistentes entre os compiladores, no entanto. As alocações de tempo de execução (pico) para o programa são as seguintes:
- GCC (C): 1.032 bytes (1 KB)
- G ++ (C ++): 73.744 bytes, (~ 74 KB)
- Clang (C): 1.032 bytes (1 KB)
- Clang ++ (C ++): 73.744 bytes (~ 74 KB)
Para compilar, eu uso os seguintes comandos:
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
Para o Valgrind, eu corro valgrind --tool=massif --massif-out-file=m_compiler_lang ./compiler-lang
em cada compilador e idioma, depois ms_print
para exibir os picos.
Estou fazendo algo errado aqui?
fonte
try
bloco às custas de uma maior quantidade de memória, talvez com uma tabela de salto ou algo assim. Talvez tente compilar sem exceções e ver qual o impacto que isso tem. Edit: De fato, iterativamente, tente desabilitar vários recursos do c ++ para ver qual o impacto que isso tem sobre o espaço ocupado pela memória.clang++ -xc
em vez declang
, a mesma alocação estava lá, o que sugere fortemente a sua função bibliotecas vinculadasC
modo e exatamente o mesmo número de bytesC++
. Você cometeu um erro de transcrição?Respostas:
O uso de heap vem da biblioteca padrão C ++. Ele aloca memória para uso da biblioteca interna na inicialização. Se você não o vincular, deve haver zero diferença entre as versões C e C ++. Com o GCC e o Clang, você pode compilar o arquivo com:
Isso instruirá o vinculador a não vincular contra bibliotecas não utilizadas. No seu código de exemplo, a biblioteca C ++ não é usada, portanto, não deve ser vinculada à biblioteca padrão C ++.
Você também pode testar isso com o arquivo C. Se você compilar com:
O uso do heap reaparecerá, mesmo que você tenha criado um programa em C.
O uso de heap é obviamente dependente da implementação específica da biblioteca C ++ que você está usando. No seu caso, essa é a biblioteca GNU C ++, libstdc ++ . Outras implementações podem não alocar a mesma quantidade de memória ou podem não alocar nenhuma memória (pelo menos não na inicialização). A biblioteca LLVM C ++ ( libc ++ ), por exemplo, não faz alocação de heap na inicialização, pelo menos no meu Linux máquina:
O uso de heap é o mesmo que não vincular nada a ele.
(Se a compilação falhar, o libc ++ provavelmente não está instalado. O nome do pacote geralmente contém "libc ++" ou "libcxx".)
fonte
-Wl,--as-needed
sinalizador remove as bibliotecas especificadas nos-l
sinalizadores, mas você não está realmente usando. Portanto, se você não usa uma biblioteca, simplesmente não vincule-a. Você não precisa desse sinalizador para isso. No entanto, se seu sistema de compilação adicionar muitas bibliotecas e seria muito trabalhoso limpá-las e vincular apenas as necessárias, você poderá usar esse sinalizador. A biblioteca padrão é uma exceção, pois é vinculada automaticamente. Portanto, este é um caso de esquina.Nem o GCC nem o Clang são compiladores - na verdade, são programas de driver de cadeia de ferramentas. Isso significa que eles invocam o compilador, o montador e o vinculador.
Se você compilar seu código com um compilador C ou C ++, obterá o mesmo assembly produzido. O Assembler produzirá os mesmos objetos. A diferença é que o driver da cadeia de ferramentas fornecerá uma entrada diferente para o vinculador para os dois idiomas diferentes: inicializações diferentes (o C ++ requer código para executar construtores e destruidores para objetos com duração de armazenamento estático ou local de encadeamento no nível do namespace e requer infraestrutura para a pilha quadros para suportar o desenrolamento durante o processamento de exceção, por exemplo), a biblioteca padrão C ++ (que também possui objetos com duração de armazenamento estático no nível do espaço para nome) e provavelmente bibliotecas de tempo de execução adicionais (por exemplo, libgcc com sua infraestrutura de desenrolamento de pilha).
Em suma, não é o compilador que está causando o aumento da área ocupada, é a vinculação de itens que você escolheu usar escolhendo a linguagem C ++.
É verdade que o C ++ tem a filosofia "pague apenas pelo que você usa", mas usando a linguagem, você paga. Você pode desativar partes da linguagem (RTTI, manipulação de exceções), mas não usa mais o C ++. Como mencionado em outra resposta, se você não usar a biblioteca padrão, poderá instruir o driver a deixar isso de fora (--Wl, - conforme necessário), mas se você não usar nenhum dos recursos do C ++ ou de sua biblioteca, por que você está escolhendo o C ++ como linguagem de programação?
fonte