He notado que siempre he usado int y doubles, sin importar cuán pequeño o grande deba ser el número. Entonces, en Java, ¿es más eficiente usar byte
o en short
lugar de int
y en float
lugar de double
?
Así que suponga que tengo un programa con muchas entradas y dobles. ¿Valdría la pena revisar y cambiar mis entradas a bytes o cortos si supiera que el número encajaría?
Sé que Java no tiene tipos sin firmar, pero ¿hay algo adicional que pudiera hacer si supiera que el número solo sería positivo?
Por eficiente me refiero principalmente a procesamiento. Asumiría que el recolector de basura sería mucho más rápido si todas las variables fueran de la mitad del tamaño y que los cálculos probablemente también serían algo más rápidos. (Supongo que, como estoy trabajando en Android, también debo preocuparme un poco por la RAM)
(Asumiría que el recolector de basura solo se ocupa de Objetos y no de primitivos, pero aún elimina todos los primitivos en los objetos abandonados, ¿verdad?)
Lo probé con una pequeña aplicación para Android que tengo, pero realmente no noté ninguna diferencia. (Aunque no medí nada "científicamente").
¿Me equivoco al suponer que debería ser más rápido y más eficiente? Odiaría pasar y cambiar todo en un programa masivo para descubrir que perdí el tiempo.
¿Valdría la pena hacerlo desde el principio cuando empiezo un nuevo proyecto? (Quiero decir, creo que todo ayudaría, pero de nuevo, si es así, ¿por qué parece que nadie lo hace?)
fuente
Eso depende de la implementación de la JVM, así como del hardware subyacente. La mayor parte del hardware moderno no obtendrá bytes individuales de la memoria (ni siquiera de la caché de primer nivel), es decir, el uso de tipos primitivos más pequeños generalmente no reduce el consumo de ancho de banda de la memoria. Asimismo, las CPU modernas tienen un tamaño de palabra de 64 bits. Pueden realizar operaciones en menos bits, pero eso funciona descartando los bits adicionales, que tampoco es más rápido.
El único beneficio es que los tipos primitivos más pequeños pueden dar como resultado un diseño de memoria más compacto, sobre todo cuando se utilizan matrices. Esto ahorra memoria, lo que puede mejorar la localidad de referencia (reduciendo así el número de pérdidas de caché) y reducir la sobrecarga de recolección de basura.
Sin embargo, en términos generales, usar los tipos primitivos más pequeños no es más rápido.
Para demostrarlo, observe el siguiente punto de referencia:
que se imprime en mi cuaderno algo viejo (agregando espacios para ajustar columnas):
Como puede ver, las diferencias de rendimiento son bastante menores. La optimización de los algoritmos es mucho más importante que la elección del tipo primitivo.
fuente
short
ybyte
son más eficientes cuando se almacenan en matrices que son lo suficientemente grandes como para importar (cuanto más grande es la matriz, mayor es la diferencia de eficiencia; abyte[2]
podría ser más o menos eficiente que anint[2]
, pero no lo suficiente como para importar de cualquier manera), pero que los valores individuales se almacenan de manera más eficiente comoint
.Usar en
byte
lugar deint
puede aumentar el rendimiento si los usa en una gran cantidad. Aquí hay un experimento:}
Esta clase prueba la velocidad de creación de un nuevo
TestClass
. Cada prueba lo hace 20 millones de veces y hay 50 pruebas.Aquí está la TestClass:
Ejecuté la
SpeedTest
clase y al final obtuve esto:Ahora estoy cambiando las entradas en bytes en TestClass y ejecutándolo de nuevo. Aquí está el resultado:
Creo que este experimento muestra que si está instalando una gran cantidad de variables, el uso de bytes en lugar de int puede aumentar la eficiencia.
fuente
byte
podría ser >> más lento << queint
.Por lo general, se considera que un byte es de 8 bits. generalmente se considera que el corto es de 16 bits.
En un entorno "puro", que no es Java, ya que todas las implementaciones de bytes y longs, cortos y otras cosas divertidas generalmente están ocultas para usted, byte hace un mejor uso del espacio.
Sin embargo, su computadora probablemente no sea de 8 bits y probablemente no sea de 16 bits. esto significa que para obtener 16 u 8 bits en particular, necesitaría recurrir a "trucos" que hacen perder tiempo para pretender que tiene la capacidad de acceder a esos tipos cuando sea necesario.
En este punto, depende de cómo se implemente el hardware. Sin embargo, según me han enseñado, la mejor velocidad se logra almacenando cosas en fragmentos que sean cómodos de usar para su CPU. A un procesador de 64 bits le gusta lidiar con elementos de 64 bits, y cualquier cosa menos que eso a menudo requiere "magia de ingeniería" para fingir que le gusta lidiar con ellos.
fuente
Una de las razones por las que short / byte / char tiene menos rendimiento es la falta de soporte directo para estos tipos de datos. Por soporte directo, es decir, las especificaciones de JVM no mencionan ningún conjunto de instrucciones para estos tipos de datos. Las instrucciones como almacenar, cargar, agregar, etc. tienen versiones para el tipo de datos int. Pero no tienen versiones para short / byte / char. Por ejemplo, considere el siguiente código java:
Lo mismo se convierte en código de máquina como se muestra a continuación.
Ahora, considere cambiar int a short como se muestra a continuación.
El código de máquina correspondiente cambiará de la siguiente manera:
Como puede observar, para manipular el tipo de datos corto, todavía se usa la versión de instrucción de tipo de datos int y convierte explícitamente int en corto cuando es necesario. Ahora, debido a esto, el rendimiento se reduce.
Ahora, la razón citada para no brindar apoyo directo de la siguiente manera:
Citado de la especificación JVM presente aquí (Página 58).
fuente
javac
compilador y no se pueden extraer inferencias fiables sobre cómo funcionará el programa en la vida real. El compilador JIT compila estos códigos de bytes en las instrucciones nativas reales de la máquina y realiza una optimización bastante seria en el proceso. Si desea analizar el rendimiento del código, debe examinar las instrucciones del código nativo. (Y es complicado porque debe tener en cuenta el comportamiento de sincronización de una canalización x86_64 de varias etapas).¡La diferencia apenas se nota! Es más una cuestión de diseño, adecuación, uniformidad, hábito, etc ... A veces es solo cuestión de gustos. Cuando lo único que le importa es que su programa se ponga en marcha y se sustituya
float
por unint
no daña la corrección, no veo ninguna ventaja en elegir uno u otro a menos que pueda demostrar que el uso de cualquiera de los tipos altera el rendimiento. El ajuste del rendimiento basado en tipos que son diferentes en 2 o 3 bytes es realmente lo último que debería preocuparle; Donald Knuth dijo una vez: "La optimización prematura es la raíz de todos los males" (no estoy seguro de que fuera él, edite si tiene la respuesta).fuente
float
no puede representar todos los números enteros de unaint
lata; ni puedeint
representar ningún valor no entero quefloat
pueda. Es decir, mientras que todos los valores int son un subconjunto de valores largos, un int no es un subconjunto de un float y un float no es un subconjunto de un int.substituting a float for a double
, si es así, el respondedor debería editar la respuesta. Si no responde, debería colgar la cabeza avergonzado y volver a lo básico por las razones descritas por @pst y por muchas otras razones.