2011-02-07 7 views
72

Conozco el concepto de un conjunto de constantes y el conjunto de constantes de cadena utilizado por las JVM para manejar los literales de cadena. Pero no sé qué tipo de memoria usa la JVM para almacenar los literales de constante de String. ¿La pila o el montón? Como es un literal que no está asociado con ninguna instancia, supongo que se almacenará en la pila. Pero si no es referido por ninguna instancia, el literal debe ser recolectado por la ejecución de GC (corríjame si estoy equivocado), entonces, ¿cómo se maneja eso si está almacenado en la pila?¿Dónde reside el conjunto de constantes de String de Java, el montón o la pila?

+8

¿Cómo se puede almacenar un grupo en la pila? ¿Conoces el concepto de una pila? –

+1

Hola Scrum Meister, intenté decir que no puede ser. Perdón por la convención equivocada. Con respecto a GC Recién ahora vine a saber. Gracias por eso –

+0

@TheScrumMeister - de hecho, en algunas circunstancias * pueden ser * basura recolectada. El "factor decisivo" es que el objeto de código para cualquier clase que mencione un literal de cadena tendrá una referencia al objeto String que representa el literal. –

Respuesta

51

La respuesta es técnicamente ninguna. De acuerdo con la Especificación de Máquina Virtual de Java, el área para almacenar literales de cadena está en el runtime constant pool. El área de memoria del conjunto de la constante de tiempo de ejecución se asigna por clase o por interfaz, por lo que no está vinculada a ninguna instancia de objeto. El grupo de constante de tiempo de ejecución es un subconjunto del área de método que "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 utilizados en la inicialización de clase e instancia e inicialización del tipo de interfaz ". La especificación de VM dice que aunque el área de método es lógicamente parte del montón, no dicta que la memoria asignada en el área del método esté sujeta a la recolección de basura u otros comportamientos que estarían asociados con las estructuras de datos normales asignadas al montón .

+7

En realidad, cuando las clases se cargan en la máquina virtual, las constantes de cadena se copiarán en el montón, en un conjunto de cadenas de toda la VM (en el permgen, como dijo Stephen C), ya que los literales de cadena iguales en diferentes clases tienen que ser el mismo objeto String (por el JLS). –

+1

Gracias a todos por sus respuestas. Entendí mucho con esta discusión. Es bueno conocerte chicos :) –

+4

Paŭlo, eso es cierto para la máquina virtual de Sun, pero no necesariamente para todas las implementaciones de la JVM. Como menciona la especificación de JVM, aunque el grupo de constante de tiempo de ejecución y el área de método son lógicamente parte del montón, no tienen que tener el mismo comportamiento.Solo una pequeña diferencia semántica, realmente :) –

24

Los literales de cadena no se almacenan en la pila.

Los literales de cadena (o más exactamente, los objetos String que los representan) son históricamente almacenados en un Heap llamado el montón "permgen". (Permgen es la abreviatura de generación permanente.)

En circunstancias normales, los literales de cadena y muchas otras cosas en el montón de permgen son "permanentemente" alcanzables, y no son basura. (Por ejemplo, los literales de cadena siempre son accesibles desde los objetos de código que los usan). Sin embargo, puede configurar una JVM para intentar encontrar y recopilar clases cargadas dinámicamente que ya no son necesarias, y esto puede causar que los literales de cadena sean basura recolectada .

CLARIFICACIÓN # 1 - No estoy diciendo que Permgen no reciba GC. Lo hace, generalmente cuando la JVM decide ejecutar un GC completo. Mi punto es que String literales será accesible siempre que se pueda acceder al código que los utiliza, y se podrá acceder al código siempre que se pueda acceder al cargador de clase del código, y para los cargadores de clase predeterminados, eso significa "para siempre".

CLARIFICACIÓN # 2 - De hecho, Java 7 almacena objetos Intern'd String en el Heap normal. Esto incluye (supongo) el objeto de cadena que representa los literales de cadena. (Consulte la respuesta de @ assylias para obtener más información.)

+1

La recolección de basura del "permgen" ocurre cuando se deshace la aplicación del servidor de aplicaciones. –

+0

@PiotrFindeisen - eso no es correcto. Sin embargo, es cierto que una gran cantidad de objetos permgen * pueden * no ser accesibles cuando cancelas la aplicación. –

+0

No creo que sus afirmaciones sobre ClassLoaders sean correctas. No es un ClassLoader alcanzable que impide que sus clases se descarguen y GC'd, es una referencia a los objetos de clase o instancias de la clase. El WebappClassLoader (sic) de Tomcat a partir de v6.x y 7.x tiene un caché "resourceEntries" que es un caché ilimitado de todas las clases cargadas. Esto evita la descarga incluso si no hay otros refs. Tal vez esta es la razón por la que tan poca gente ve descargar clases. –

41

Como se explica por this answer, la ubicación exacta del grupo de cadenas no está especificada y puede variar de una implementación de JVM a otra.

Es interesante notar que hasta Java 7, la piscina estaba en el espacio PermGen del montón de JVM punto de acceso, pero it has been moved to the main part of the heap since Java 7:

Área: HotSpot
Sinopsis: En el JDK 7 , las cadenas internas ya no se asignan en la generación permanente del montón de Java, pero se asignan en su lugar en la parte principal del montón Java (conocido como generaciones jóvenes y antiguas), junto con otros objetos creados por la aplicación. Este cambio dará como resultado más datos que residen en el montón principal de Java y menos datos en la generación permanente, y por lo tanto puede requerir que se ajusten los tamaños de almacenamiento dinámico. La mayoría de las aplicaciones solo verán diferencias relativamente pequeñas en el uso del montón debido a este cambio, pero las aplicaciones más grandes que cargan muchas clases o hacen un uso intensivo del método String.intern() verán diferencias más significativas. RFE: 6962931

Y en Java 8 Hotspot, la generación permanente se ha eliminado por completo.

+0

Gracias por esta información. – xuanyuanzhiyuan

+0

Buena explicación. –

+0

gracias por educar, pero todavía estoy tratando de encontrar una línea delgada entre el almacenamiento de la cadena literal y la cadena creada con el nuevo – VedX

19

cadena puesta en común de

cadena puesta en común (a veces también llamado como canonicalisation cadena) es un proceso de sustitución de varios objetos String con igual valor, pero identidad diferente con un único objeto String compartido . Puede lograr este objetivo manteniendo su propio mapa (posiblemente o las referencias débiles dependiendo de sus requisitos) y utilizando los valores del mapa como valores canonicalizados. O puede usar el método String.intern() que le proporciona JDK.

En momentos de Java 6 utilizando String.intern() estaba prohibido por muchas normas debido a una alta posibilidad de obtener una OutOfMemoryException si puesta en común se salió de control. La implementación de Oracle Java 7 de la cadena se modificó considerablemente. Puede buscar detalles en http://bugs.sun.com/view_bug.do?bug_id=6962931 y http://bugs.sun.com/view_bug.do?bug_id=6962930.

String.intern() en Java 6

En aquellos buenos viejos todas las cadenas internados se almacenan en la PermGen - el tamaño fijo parte del montón utiliza principalmente para el almacenamiento de clases cargadas y grupo de cuerdas. Además de las cadenas explícitamente internados, el conjunto de cadenas PermGen también contenía todas las cadenas literales utilizadas anteriormente en tu programa (se usa la palabra importante aquí; si una clase o método nunca fue cargado , las constantes definidas en él no se cargarán) .

El mayor problema con dicho grupo de cadenas en Java 6 era su ubicación: PermGen. PermGen tiene un tamaño fijo y no se puede expandir en el tiempo de ejecución . Puede configurarlo usando la opción -XX: MaxPermSize = 96m. En cuanto a I saber, el tamaño predeterminado de PermGen varía entre 32M y 96M dependiendo de la plataforma. Puede aumentar su tamaño, pero su tamaño seguirá siendo fijo. Dicha limitación requiere un uso muy cuidadoso de String.pasante - es mejor no internar ninguna entrada de usuario no controlada utilizando este método. Es por eso que la agrupación de cadenas en momentos de Java 6 se implementó principalmente en los mapas administrados manualmente.

String.intern() en Java 7

ingenieros de Oracle hizo un cambio muy importante a la lógica de la agrupación de cuerdas en Java 7 - el grupo de cadena se trasladó al montón. Significa que ya no está limitado por un área de memoria de tamaño fijo . Todas las cadenas se encuentran ahora en el montón, como la mayoría de los demás objetos ordinarios , lo que le permite administrar solo el tamaño del montón mientras ajusta su aplicación. Técnicamente, esto solo podría ser un motivo suficiente para reconsiderar el uso de String.intern() en los programas de Java 7. Pero hay otras razones.

valores de grupo de cadena son basura recogida

Sí, todas las cadenas en el grupo de cadena JVM son aptos para reciclaje si no hay referencias a ellos desde sus raíces del programa. Se aplica a todas las versiones discutidas de Java. Significa que si su cadena interna salió del alcance y no hay otras referencias a , será basura recolectada del grupo de cadenas JVM.

Al ser elegible para la recolección de basura y residir en el montón, un grupo de cadenas JVM parece ser el lugar adecuado para todas las cadenas, ¿no? En teoría es cierto: las cadenas no utilizadas serán basura recolectada de el grupo, las cadenas usadas le permitirán guardar la memoria en caso de que obtenga una cadena igual de la entrada. Parece ser una memoria perfecta estrategia de ahorro? Casi así. Debe saber cómo se implementó el conjunto de cadenas de caracteres antes de tomar cualquier decisión.

source.

2

Para las grandes respuestas que ya incluye aquí quiero añadir algo que falta en mi punto de vista - y la ilustración.

Como ya lo hace, JVM divide la memoria asignada a un programa Java en dos partes. uno es pila y otro es montón. Stack se usa con fines de ejecución y Heap se usa con fines de almacenamiento. En esa memoria Heap, JVM asigna memoria especialmente pensada para literales de cadena. Esta parte de la memoria del montón se llama conjunto de constantes de cadena.

Así, por ejemplo, si INIT los siguientes objetos:

String s1 = "abc"; 
String s2 = "123"; 
String obj1 = new String("abc"); 
String obj2 = new String("def"); 
String obj3 = new String("456); 

literales de cadena s1 y s2 se destinará a la cadena del grupo de constantes, objetos obj1, obj2, obj3 al montón. Todos ellos, serán referenciados desde la Pila.

Además, tenga en cuenta que "abc" aparecerá en el montón y en el conjunto constante de cadenas. ¿Por qué se crearán String s1 = "abc" y String obj1 = new String("abc") de esta manera? Es porque String obj1 = new String("abc") crea explícitamente una nueva instancia distinta de un objeto String y String s1 = "abc" puede reutilizar una instancia del conjunto constante de cadenas si hay una disponible. Para una explicación más elaborada: https://stackoverflow.com/a/3298542/2811258

enter image description here

+0

En el diagrama dado, ¿dónde existirían los literales "def" y "456"? ¿Y cómo se hace referencia a estos? – Satyendra

+0

Gracias por su comentario @Satyendra, he actualizado la ilustración y la respuesta. – Stas

+0

@Stas por qué se crea otro objeto String "abc" ... debe usar la referencia obj1 para señalar el literal ¿correcto? –

2

Como explican otras respuestas de memoria en Java se divide en dos porciones

1. Pila: Una pila se crea por hilo y almacena los marcos de pila, que de nuevo almacena variables locales y si una variable es un tipo de referencia, esa variable hace referencia a una ubicación de memoria en el montón para el objeto real.

2. Heap: Todo tipo de objetos se crearán solo en el montón.

memoria de almacenamiento dinámico se dividen a su vez en 3 porciones

1. Generación Joven: Tiendas objetos que tienen una vida breve, el propio Young Generation se puede dividir en dos categorías Eden espacio y el espacio superviviente de.

2. Generación anterior: Almacenar objetos que han sobrevivido a muchos ciclos de recolección de basura y aún se hace referencia a ellos.

3. Generación permanente: Almacena metadatos sobre el programa, p. conjunto de constante de tiempo de ejecución

El grupo de constante de cadena pertenece al área de generación permanente de la memoria Heap.

Como se discutió en How Does JVM Handle Method Overloading and Overriding Internally, podemos ver la piscina constante de tiempo de ejecución para nuestro código en el código de bytes mediante el uso de javap -verbose class_name que nos mostrará referencias de métodos (#Methodref), objetos de clase (#Class), literales de cadena (#String)

runtime-constant-pool

Cuestiones relacionadas