Cuando se usa el mismo código, simplemente cambiando el compilador (de un compilador C a un compilador C ++) cambiará la cantidad de memoria asignada. No estoy muy seguro de por qué es así y me gustaría entenderlo más. Hasta ahora, la mejor respuesta que he recibido es "probablemente las transmisiones de E / S", que no es muy descriptiva y me hace preguntarme sobre el aspecto "no paga por lo que no usa" de C ++.
Estoy usando los compiladores Clang y GCC, versiones 7.0.1-8 y 8.3.0-6 respectivamente. Mi sistema se ejecuta en Debian 10 (Buster), la última. Los puntos de referencia se realizan a través del macizo Valgrind.
#include <stdio.h>
int main() {
printf("Hello, world!\n");
return 0;
}
El código utilizado no cambia, pero si compilo como C o como C ++, cambia los resultados del benchmark Valgrind. Sin embargo, los valores permanecen consistentes entre los compiladores. Las asignaciones de tiempo de ejecución (pico) para el programa son las siguientes:
- CCG (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, uso los siguientes 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 Valgrind, ejecuto valgrind --tool=massif --massif-out-file=m_compiler_lang ./compiler-lang
en cada compilador e idioma, luego ms_print
para mostrar los picos.
¿Estoy haciendo algo mal aquí?
fuente
try
bloque a expensas de una huella de memoria más grande, tal vez con una tabla de salto o algo así. Tal vez intente compilar sin excepciones y ver qué impacto tiene. Editar: de hecho, intente deshabilitar iterativamente varias funciones de c ++ para ver qué impacto tiene en la huella de la memoria.clang++ -xc
lugar declang
, la misma asignación estaba allí, lo que sugiere que se debe a las bibliotecas vinculadasC
modo y exactamente el mismo número de bytes enC++
modo. ¿Cometiste un error de transcripción?Respuestas:
El uso del montón proviene de la biblioteca estándar de C ++. Asigna memoria para el uso interno de la biblioteca al inicio. Si no se vincula con él, debería haber una diferencia cero entre la versión C y C ++. Con GCC y Clang, puede compilar el archivo con:
Esto le indicará al vinculador que no se vincule contra bibliotecas no utilizadas. En su código de ejemplo, la biblioteca de C ++ no se usa, por lo que no debe vincularse con la biblioteca estándar de C ++.
También puede probar esto con el archivo C. Si compila con:
El uso del montón volverá a aparecer, aunque haya creado un programa en C.
El uso del montón obviamente depende de la implementación específica de la biblioteca C ++ que está utilizando. En su caso, esa es la biblioteca GNU C ++, libstdc ++ . Otras implementaciones podrían no asignar la misma cantidad de memoria, o puede ser que no se asignará ningún recuerdo en absoluto (al menos no en el arranque.) La biblioteca de LLVM C ++ ( libc ++ ), por ejemplo, no hace asignación del montón en el arranque, por lo menos en mi Linux máquina:
El uso de almacenamiento dinámico es lo mismo que no vincularse en absoluto contra él.
(Si la compilación falla, probablemente libc ++ no esté instalado. El nombre del paquete generalmente contiene "libc ++" o "libcxx").
fuente
-Wl,--as-needed
indicador elimina las bibliotecas que especifique en sus-l
indicadores, pero que en realidad no está utilizando. Entonces, si no usa una biblioteca, simplemente no se vincule contra ella. No necesitas esta bandera para esto. Sin embargo, si su sistema de compilación agrega demasiadas bibliotecas y sería mucho trabajo limpiarlas todas y vincular solo las necesarias, entonces puede usar este indicador en su lugar. Sin embargo, la biblioteca estándar es una excepción, ya que está vinculada automáticamente. Entonces este es un caso de esquina.Ni GCC ni Clang son compiladores, en realidad son programas de controladores de cadena de herramientas. Eso significa que invocan el compilador, el ensamblador y el enlazador.
Si compila su código con un compilador C o C ++, obtendrá el mismo ensamblado producido. El ensamblador producirá los mismos objetos. La diferencia es que el controlador de la cadena de herramientas proporcionará diferentes entradas al enlazador para los dos idiomas diferentes: diferentes inicios (C ++ requiere código para ejecutar constructores y destructores para objetos con una duración de almacenamiento local estático o de subprocesos a nivel de espacio de nombres, y requiere infraestructura para la pila marcos para admitir el desenrollado durante el procesamiento de excepciones, por ejemplo), la biblioteca estándar de C ++ (que también tiene objetos de duración de almacenamiento estático a nivel de espacio de nombres) y probablemente bibliotecas de tiempo de ejecución adicionales (por ejemplo, libgcc con su infraestructura de desenrollado de pila).
En resumen, no es el compilador el que causa el aumento de la huella, es la vinculación de las cosas que ha elegido usar al elegir el lenguaje C ++.
Es cierto que C ++ tiene la filosofía de "paga solo por lo que usas", pero al usar el lenguaje, pagas por ello. Puede deshabilitar partes del lenguaje (RTTI, manejo de excepciones) pero ya no está usando C ++. Como se mencionó en otra respuesta, si no usa la biblioteca estándar, puede indicarle al controlador que la omita (--Wl, - según sea necesario) pero si no va a usar ninguna de las funciones de C ++ o su biblioteca, ¿por qué incluso eliges C ++ como lenguaje de programación?
fuente