simple - ¿Cuál es el costo de tamaño de la herencia de Java?
relaciones entre clases programacion orientada a objetos (5)
en teoría, la sobrecarga directamente asociada a la representación en memoria de cualquier objeto Java debe ser O (1) para la profundidad de herencia N. ¿Alguien sabe si es cierto en la práctica?
No puede ser O (1) a menos que haya cero miembros de instancia en cada nivel. Cada miembro de instancia requiere espacio por instancia.
Hay varios artículos en las interwebs que intentan estimar empíricamente la sobrecarga de un java.lang.Object
en implementaciones de JVM en particular. Por ejemplo, he visto la sobrecarga de tamaño de un Object
desnudo estimado en 8 bytes en algunas JVM.
Lo que me gustaría saber es si una implementación típica de JVM de la relación extends
introduce una tara de tamaño incremental en cada nivel de la jerarquía de clases. En otras palabras, supongamos que tiene una jerarquía de clases con N niveles de subclases. ¿La sobrecarga de la representación en memoria de una instancia de clase O (1) u O (N)?
Me imagino que es O (1) porque aunque el tamaño de algunas de las cosas esponjosas ocultas que necesitas para ser un Object
Java (vtable, cadena de clases) crecerá a medida que crezca la jerarquía de herencia, crecerán por clase, no por Por ejemplo, y la implementación de JVM puede almacenar punteros de tamaño constante para estas entidades en un encabezado de tamaño constante adjunto a cada Object
.
Entonces, en teoría, la sobrecarga directamente asociada a la representación en memoria de cualquier objeto Java debe ser O (1) para la profundidad de herencia N. ¿Alguien sabe si es cierto en la práctica?
El doble y el entero, que extienden el número, que extiende el objeto, no tienen un comportamiento O (n), es decir, un entero no es 3 veces el tamaño de un objeto, por lo que creo que la respuesta es O (1). por ejemplo, ver esta vieja pregunta SO
En caso de duda, observe la source (bueno, una fuente, cada JVM puede elegir libremente cómo hacerlo, ya que la norma no exige ninguna representación interna). Así que eché un vistazo y encontré el siguiente comentario en la implementación de la JVM del punto de acceso JDK 7-u60:
// A Klass is the part of the klassOop that provides:
// 1: language level class object (method dictionary etc.)
// 2: provide vm dispatch behavior for the object
// Both functions are combined into one C++ class. The toplevel class "Klass"
// implements purpose 1 whereas all subclasses provide extra virtual functions
// for purpose 2.
// One reason for the oop/klass dichotomy in the implementation is
// that we don''t want a C++ vtbl pointer in every object. Thus,
// normal oops don''t have any virtual functions. Instead, they
// forward all "virtual" functions to their klass, which does have
// a vtbl and does the C++ dispatch depending on the object''s
La forma en que lo leí, esto significa que, para esta implementación (muy popular), las instancias de objetos solo almacenan un puntero a su clase. El costo, por instancia de una clase, de esa clase que tiene una cadena de herencia más larga o más corta es efectivamente 0 . Sin embargo, las clases sí ocupan espacio en la memoria (pero solo una vez por clase). La eficiencia en el tiempo de ejecución de las cadenas de herencia profundas es otro asunto.
Una instancia generalmente requiere los siguientes datos, aunque depende de la implementación exactamente qué hacer:
- los campos de instancia de la clase y sus clases principales, que supongo que no quiere incluir en el término "overhead"
- algunos medios para bloquear el objeto
- si el recolector de basura reubica objetos, entonces algunos medios para registrar el hash original del objeto (para
Object.hashCode
) - algunos medios para acceder a la información de tipo
A medida que adivina en su pregunta, en una implementación Java "normal" la información de tipo se almacena por clase, no por instancia. Parte de la definición de "tipo" es que dos instancias de la misma clase necesariamente tienen el mismo tipo de información, no hay una razón obvia para no compartirla. Por lo tanto, es de esperar que la sobrecarga por instancia sea constante, sin depender de la jerarquía de clases.
Es decir, agregar clases o interfaces adicionales vacías a una clase no debería aumentar el tamaño de sus instancias. No creo que ni el lenguaje ni la especificación de JVM realmente lo garanticen, así que no haga demasiadas suposiciones sobre lo que se permite hacer una implementación Java "no normal".
Como un aparte, la segunda y tercera cosas en mi lista se pueden combinar a través de astucia engañosa, por lo que ambos juntos son un solo puntero. El artículo al que se vincula hace referencia a referencias que toman 4 bytes, por lo que los 8 bytes que se obtienen para un objeto son un puntero para escribir información, un campo que contiene un código hash o un puntero a un monitor, y probablemente algunos indicadores en el más bajo 2 bits de uno o ambos campos de puntero. Object
(esperas) será mayor en una Java de 64 bits.
Los estados de especificación de JVM
Java Virtual Machine no exige ninguna estructura interna particular para objetos.
Por lo tanto, a la especificación no le importa cómo lo haga. Pero ...
En algunas implementaciones de Oracle de la máquina virtual de Java, una referencia a una instancia de clase es un puntero a un manejador que es en sí mismo un par de punteros: uno a una tabla que contiene los métodos del objeto y un puntero al objeto de clase que representa el tipo del objeto, y el otro a la memoria asignada del montón para los datos del objeto.
Entonces, en las implementaciones típicas de Oracle, es O (1) para los métodos. Esta tabla de métodos es el Área del método que es por clase.
Java Virtual Machine tiene un área de método que se comparte entre todos los subprocesos de Java Virtual Machine. El área de método es análoga al área de almacenamiento para código compilado de un lenguaje convencional o análogo al segmento de "texto" en un proceso de sistema operativo. Almacena estructuras por clase, como el grupo constante de tiempo de ejecución, datos de campo y método, y el código de métodos y constructores, incluidos los métodos especiales (§2.9) utilizados en la inicialización de clase e instancia y la inicialización de la interfaz.
Además, sobre las entradas de método
Las estructuras
method_info
representan todos los métodos declarados por esta clase o tipo de interfaz, incluidos los métodos de instancia, métodos de clase, métodos de inicialización de instancias (§2.9) y cualquier método de inicialización de clase o interfaz (§2.9). La tabla de métodos no incluye elementos que representan métodos heredados de superclases o superinterfaces.