¿Cómo se compara / contrasta el uso de memoria de un objeto entero escrito en Java con el uso de memoria de un objeto entero escrito en C ++? ¿La diferencia es insignificante? ¿Ninguna diferencia? ¿Una gran diferencia? Supongo que es lo mismo porque un int es un int independientemente del idioma (?)
La razón por la que pregunté esto es porque estaba leyendo sobre la importancia de saber cuándo los requisitos de memoria de un programa evitarán que el programador resuelva un problema dado.
Lo que me fascinó es la cantidad de memoria requerida para crear un solo objeto Java. Tomemos, por ejemplo, un objeto entero. Corrígeme si me equivoco pero un objeto entero Java requiere 24 bytes de memoria:
- 4 bytes para su variable de instancia int
- 16 bytes de sobrecarga (referencia a la clase del objeto, información de recolección de basura e información de sincronización)
- 4 bytes de relleno
Como otro ejemplo, una matriz Java (que se implementa como un objeto) requiere 48 + bytes:
- 24 bytes de información de encabezado
- 16 bytes de sobrecarga de objetos
- 4 bytes de longitud
- 4 bytes para relleno
- más la memoria necesaria para almacenar los valores
¿Cómo se comparan estos usos de memoria con el mismo código escrito en C ++?
Solía ser ajeno al uso de memoria de los programas C ++ y Java que escribí, pero ahora que estoy empezando a aprender sobre algoritmos, aprecio mucho más los recursos de la computadora.
fuente
int
? Si es así, debe comparar eso conint
Java, noInteger
, siempre que sus entradas C ++ sean de 32 bits.Respuestas:
Depende de la plataforma y la implementación.
C ++ garantiza que el tamaño de
char
es exactamente un byte y al menos 8 bits de ancho. Entonces, el tamaño de ashort int
es de al menos 16 bits y no menor quechar
. El tamaño de unint
es al menos tan grande como el tamaño deshort int
. El tamañolong int
es de al menos 32 bits y no menor que int.sizeof(char) == 1; sizeof(long int) >= sizeof(int) >= sizeof(short int) >= sizeof(bool) >= sizeof(char).
Sin embargo, el modelo de memoria real de C ++ es muy compacto y predecible . Por ejemplo, no hay metadatos en objetos, matrices o punteros. Las estructuras y las clases son contiguas al igual que las matrices, pero el relleno puede colocarse donde sea necesario y necesario.
Francamente, tal comparación es tonta en el mejor de los casos, ya que el uso de la memoria Java depende más de la implementación de Java que del código que ejecuta.
fuente
int32_t
.La mayoría de las respuestas parecen ignorar un par de puntos bastante importantes.
Primero, en una gran cantidad de Java, prácticamente nunca se ve un raw
int
; casi todo el uso es útilInteger
, por lo que el hecho de que unint
podría ser (aproximadamente) del mismo tamaño que unint
en C o C ++ es casi irrelevante, excepto por eso ( en mi experiencia, pequeño) porcentaje de código que solo usa enint
lugar deInteger
.En segundo lugar, el tamaño de los objetos individuales no tiene casi nada que ver con la huella de memoria de un programa en su conjunto. En Java, la huella de memoria del programa se relaciona principalmente con cómo se ha ajustado el recolector de basura. En la mayoría de los casos, el GC se ajusta para maximizar la velocidad, lo que (en gran medida) significa ejecutar el GC con la menor frecuencia posible.
No tengo un enlace a mano en este momento, pero se han realizado algunas pruebas que muestran que Java puede correr a la misma velocidad que C, pero para hacerlo hay que ejecutar el GC raramente lo suficiente como para usar alrededor de 7 veces más memoria. Esto no se debe a que los objetos individuales sean 7 veces más grandes, sino a que GC puede ser bastante costoso si lo hace con demasiada frecuencia. Peor aún, GC solo puede liberar memoria cuando puede "probar" que ya no hay ninguna forma de acceder a un objeto, en lugar de simplemente cuando sabes que ya no lo usas. Esto significa que incluso si ejecuta el GC con mucha más frecuencia para minimizar el uso de memoria, probablemente aún pueda planificar que un programa típico tenga una huella de memoria que sea mayor. En un caso como este, puede reducir el factor a 2 o 3 en lugar de 7. Sin embargo, aunque vaya drásticamente por la borda, no lo haga.1 .
Dependiendo de la situación, hay otro factor que puede o no ser significativo: la memoria ocupada por la propia JVM. Esto es más o menos fijo, por lo que, como porcentaje, puede ser enorme si la aplicación no necesita mucho almacenamiento propio, o puede ser minúsculo si la aplicación necesita almacenar mucho. Al menos en mi máquina, incluso la aplicación Java más trivial parece ocupar algo así como 20-25 megabytes (podría ser más de 1000x para programas trivlal, o casi inconmensurablemente pequeña para los grandes).
1 Eso no quiere decir que nadie podría lograr escribir Java con una huella tan cercana a lo que obtendría con C ++. Es solo para decir que solo tener el mismo número / tamaño de objetos y ejecutar el GC con mucha frecuencia no lo llevará a eso por regla general.
fuente
Integer
(¿por qué lo harían?) En lugar deint
. Solo las colecciones genéricas no tienen más opción que usarInteger
debido a la eliminación de tipos, pero si le importa, puede reemplazarlas con una implementación especializadaint
o cualquier tipo primitivo que necesite. Y luego está el boxeo temporal para pasar por el código genérico de envoltura (por ejemplo, todo lo que requiere unObject[]
). Además de eso, ¿tiene fuentes para la sobrecarga del espacio GC? Realmente no lo dudo, simplemente tengo curiosidad.Espero que se den cuenta de que todo esto está profundamente definido en la implementación, tanto para Java como para C ++. Dicho esto, el modelo de objetos de Java requiere bastante espacio.
Los objetos C ++ no necesitan (generalmente) ningún almacenamiento, excepto lo que necesitan los miembros. Tenga en cuenta que (a diferencia de Java, donde todo lo definido por el usuario es un tipo de referencia), el código del cliente puede usar objetos como tipo de valor o como tipos de referencia, es decir, un objeto podría almacenar un puntero / referencia a otro objeto, o almacenar el objeto directamente sin indirección Es necesario un puntero adicional por objeto si hay algún
virtual
método, pero algunas clases útiles están diseñadas para llevarse bien sin polimorfismo y no lo necesitan. No hay metadatos GC ni bloqueo por objeto. Por lo tanto, losclass IntWrapper { int x; public: IntWrapper(int); ... };
objetos no necesitan más espacio que los simplesint
, y se pueden colocar directamente (es decir, sin indirección) en colecciones y otros objetos.Las matrices son complicadas simplemente porque no hay un equivalente común prefabricado a una matriz de Java en C ++. Simplemente podría asignar un grupo de objetos con
new[]
(sin sobrecarga / metadatos) pero no hay un campo de longitud; la implementación probablemente almacena uno pero no puede acceder a él.std::vector
es una matriz dinámica y por lo tanto tiene una sobrecarga adicional y una interfaz más grande.std::array
y matrices de estilo C (int arr[N];
), necesita una constante de tiempo de compilación. En teoría, debería ser solo el almacenamiento del objeto más un número entero para la longitud, pero dado que puede obtener un cambio de tamaño dinámico y una interfaz con todas las funciones con muy poco espacio extra, simplemente vaya por eso en la práctica. Tenga en cuenta que todas estas, así como todas las demás colecciones, predeterminan el almacenamiento de los objetos por valor, lo que le ahorra indirección y el espacio para referencias, y mejora el comportamiento de la memoria caché. Debe almacenar explícitamente los punteros (los inteligentes, por favor) para obtener la indirección.Las comparaciones anteriores no son del todo justas, porque algunos de estos ahorros se obtienen al no incluir las características que incluye Java, y su equivalente de C ++ a menudo está menos optimizado que el equivalente de Java (*). La forma común de implementar
virtual
en C ++ impone exactamente la misma sobrecarga que la forma común de implementarvirtual
en Java. Para obtener un bloqueo, necesita un objeto mutex con todas las funciones, que probablemente sea más grande que unos pocos bits. Para obtener el recuento de referencia ( noequivalente a GC, y no debe usarse como tal, pero a veces útil), necesita un puntero inteligente que agregue un campo de recuento de referencia. A menos que el objeto se construya con cuidado, el recuento de referencias, el objeto de puntero inteligente y el objeto de referencia están en ubicaciones completamente separadas, e incluso cuando lo construye correctamente, el puntero compartido puede (¿debe?) Seguir siendo dos punteros en lugar de uno. Por otra parte, un buen estilo de C ++ no utiliza estas características lo suficiente como para que importe: en la práctica, los objetos de una biblioteca de C ++ bien escritos usan menos. Eso no necesariamente significa menos uso de memoria en general, pero sí significa que C ++ tiene una buena ventaja en este sentido.(*) Por ejemplo, puede obtener llamadas virtuales, códigos hash de identidad y bloqueo con solo una palabra para algunos objetos (y dos palabras para muchos otros objetos) fusionando la información de tipo con varios indicadores y eliminando bits de bloqueo para objetos que son Es poco probable que necesite cerraduras. Para obtener una explicación detallada de esta y otras optimizaciones, vea Implementación eficiente en tiempo y espacio del modelo de objetos Java (PDF) de David F. Bacon, Stephen J. Fink y David Grove.
fuente
Un plano
int
, en java, ocupa exactamente tanto espacio comoint
en C ++, siempre que ambas implementaciones usen el mismo tamaño de entero y alineación de memoria.Un int 'objeto' (un entero en caja , es decir, una instancia de clase
Integer
), lleva toda la sobrecarga de una instancia de clase en Java, por lo que es significativamente más grande que unint
en C ++. Sin embargo, si tuviera que equipar un objeto en C ++ con las mismas características que los objetos Java vienen de fábrica (polimorfismo, boxeo, recolección de basura, RTTI), entonces probablemente terminaría con un objeto de igual Talla.Y luego hay consideraciones de optimización; Dado que los modelos de ejecución y los paradigmas de programación difieren, es poco probable que cualquier problema no trivial se resuelva de la misma manera en ambos idiomas, por lo que comparar el tamaño de almacenamiento en este nivel no tiene mucho sentido.
Sí, los objetos Java llevan más sobrecarga por defecto que las clases de C ++, pero vienen con más características, y esto lleva a un estilo de programación diferente: un buen programador puede aprovechar las ventajas y desventajas de cualquier lenguaje.
fuente