asignación estática en java: pila, pila y generación permanente

117

Últimamente he estado leyendo mucho sobre esquemas de asignación de memoria en Java, y ha habido muchas dudas ya que he estado leyendo de varias fuentes. He recopilado mis conceptos y solicitaría repasar todos los puntos y comentarlos. Llegué a saber que la asignación de memoria es específica de JVM, por lo que debo decir de antemano que mi pregunta es específica de Sun.

  1. Las clases (cargadas por los cargadores de clases) van en un área especial en el montón: Generación permanente
  2. Toda la información relacionada con una clase como el nombre de la clase, las matrices de objetos asociadas con la clase, los objetos internos utilizados por JVM (como java / lang / Object) y la información de optimización entra en el área de generación permanente.
  3. Todas las variables miembro estáticas se mantienen nuevamente en el área de Generación permanente.
  4. Los objetos van en un montón diferente: generación joven
  5. Solo hay una copia de cada método por clase, ya sea el método estático o no estático. Esa copia se coloca en el área de Generación Permanente. Para los métodos no estáticos, todos los parámetros y variables locales van a la pila, y cada vez que hay una invocación concreta de ese método, obtenemos un nuevo marco de pila asociado con él. No estoy seguro de dónde se almacenan las variables locales de un método estático. ¿Están en el montón de la generación permanente? O simplemente su referencia se almacena en el área de Generación permanente, y la copia real está en otro lugar (¿Dónde?)
  6. Tampoco estoy seguro de dónde se almacena el tipo de retorno de un método.
  7. Si los objetos (en la generación joven) necesitan usar un miembro estático (en la generación permanente), se les da una referencia al miembro estático && se les da suficiente espacio de memoria para almacenar el tipo de retorno del método, etc.

¡Gracias por pasar por esto!

Jaguar
fuente

Respuestas:

152

Primero, como ya debería estar claro para usted, hay muy pocas personas que puedan confirmar estas respuestas con conocimiento de primera mano. Muy pocas personas han trabajado en JVM HotSpot recientes o las han estudiado con la profundidad necesaria para saberlo realmente. La mayoría de las personas aquí (incluido yo mismo) están respondiendo basándose en cosas que han visto escritas en otro lugar, o lo que han inferido. Por lo general, lo que está escrito aquí, o en varios artículos y páginas web, se basa en otras fuentes que pueden o no ser definitivas. A menudo es simplificado, inexacto o simplemente incorrecto.

Si desea una confirmación definitiva de sus respuestas, realmente necesita descargar el código fuente de OpenJDK ... y hacer su propia investigación leyendo y entendiendo el código fuente. Hacer preguntas sobre SO, o rastrear artículos web aleatorios no es una técnica de investigación académica sólida.

Una vez dicho esto ...

... mi pregunta es específica de Sun.

En el momento en que se hizo esta pregunta, Sun Microsystems había dejado de existir. Por lo tanto, la pregunta era específica de Oracle. AFAIK, todas las implementaciones actuales de JVM de terceros (que no son de investigación) son puertos directos de una versión de OpenJDK o descienden de otra versión de Sun / Oracle.

Las respuestas a continuación se aplican a las versiones de Oracle Hotspot y OpenJDK, y probablemente también a la mayoría de las demás ... incluido GraalVM.

1) Las clases (cargadas por los cargadores de clases) van en un área especial en el montón: Generación permanente.

Antes de Java 8, sí.

A partir de Java 8, el espacio de PermGen ha sido reemplazado por Metaspace. Las clases cargadas y compiladas con JIT ahora van allí. PermGen ya no existe.

2) Toda la información relacionada con una clase como el nombre de la clase, las matrices de objetos asociadas con la clase, los objetos internos utilizados por JVM (como java / lang / Object) y la información de optimización entra en el área de generación permanente.

Más o menos, sí. No estoy seguro de a qué te refieres con algunas de esas cosas. Supongo que "objetos internos utilizados por JVM (como java / lang / Object)" significa descriptores de clase internos de JVM.

3) Todas las variables miembro estáticas se mantienen nuevamente en el área de Generación Permanente.

Las propias variables sí. Estas variables (como todas las variables de Java) contendrán valores primitivos o referencias a objetos. Sin embargo, mientras que las variables miembro estáticas están en un marco que se asigna en el montón de permgen, los objetos / matrices a los que hacen referencia esas variables se pueden asignar en cualquier montón.

4) Los objetos van en un montón diferente: generación joven

No necesariamente. Los objetos grandes pueden asignarse directamente a la generación titular.

5) Solo hay una copia de cada método por clase, ya sea el método estático o no estático. Esa copia se coloca en el área de Generación Permanente.

Suponiendo que te refieres al código del método, entonces AFAIK sí. Sin embargo, puede ser un poco más complicado. Por ejemplo, ese código puede existir en forma de código de bytes y / o código nativo en diferentes momentos durante la vida de la JVM.

... Para los métodos no estáticos, todos los parámetros y variables locales van a la pila, y cada vez que hay una invocación concreta de ese método, obtenemos un nuevo marco de pila asociado.

Si.

... No estoy seguro de dónde se almacenan las variables locales de un método estático. ¿Están en el montón de la generación permanente? O simplemente su referencia se almacena en el área de Generación permanente, y la copia real está en otro lugar (¿Dónde?)

No. Se almacenan en la pila, al igual que las variables locales en métodos no estáticos.

6) Tampoco estoy seguro de dónde se almacena el tipo de retorno de un método.

Si se refiere al valor devuelto por una llamada al método (no nula), entonces se devuelve en la pila o en un registro de máquina. Si se devuelve en la pila, se necesitan 1 o dos palabras, según el tipo de devolución.

7) Si los objetos (en la generación joven) necesitan usar un miembro estático (en la generación permanente), se les da una referencia al miembro estático && se les da suficiente espacio de memoria para almacenar el tipo de retorno del método, etc. .

Eso es inexacto (o al menos, no se está expresando con claridad).

Si algún método accede a una variable miembro estática, lo que obtiene es un valor primitivo o una referencia de objeto . Esto puede asignarse a una variable o parámetro local (existente), asignarse a un miembro (existente) estático o no estático, asignarse a un elemento (existente) de una matriz previamente asignada, o simplemente usarse y descartarse.

  • En ningún caso es necesario asignar un nuevo almacenamiento para contener una referencia o un valor primitivo.

  • Normalmente, una palabra de memoria es todo lo que se necesita para almacenar un objeto o una referencia de matriz, y un valor primitivo suele ocupar una o dos palabras, dependiendo de la arquitectura del hardware.

  • En ningún caso la persona que llama necesita asignar espacio para contener algún objeto / matriz devuelto por un método. En Java, los objetos y las matrices siempre se devuelven utilizando la semántica de paso por valor ... pero ese valor que se devuelve es un objeto o una referencia de matriz.


Para obtener más información, consulte estos recursos:

Stephen C
fuente