Según tengo entendido, en Java, la memoria de pila contiene primitivas e invocaciones de métodos y la memoria de montón se usa para almacenar objetos.
Supongamos que tengo una clase
class A {
int a ;
String b;
//getters and setters
}
¿Dónde se almacenará el primitivo
a
en claseA
?¿Por qué existe la memoria de montón? ¿Por qué no podemos almacenar todo en la pila?
Cuando el objeto se recolecta, ¿se destruye la pila asociada con el objeto?
Respuestas:
La diferencia básica entre stack y heap es el ciclo de vida de los valores.
Los valores de pila solo existen dentro del alcance de la función en la que se crean. Una vez que regresa, se descartan.
Sin embargo, existen valores de montón en el montón. Se crean en algún momento y se destruyen en otro (ya sea por GC o manualmente, dependiendo del idioma / tiempo de ejecución).
Ahora Java solo almacena primitivas en la pila. Esto mantiene la pila pequeña y ayuda a mantener pequeños los marcos de pila individuales, permitiendo así más llamadas anidadas.
Los objetos se crean en el montón y solo las referencias (que a su vez son primitivas) se pasan en la pila.
Entonces, si crea un objeto, se coloca en el montón, con todas las variables que le pertenecen, para que pueda persistir después de que regrese la llamada a la función.
fuente
char
s son números y se pueden usar indistintamente como tal. Las referencias también son solo números que se refieren a una dirección de memoria, ya sea de 32 o 64 bits de largo (aunque no se pueden usar como tales, a menos que esté jugandosun.misc.Unsafe
).boolean
,byte
,short
,char
,int
,long
,float
Ydouble
.)¿Dónde se almacenan los campos primitivos?
Los campos primitivos se almacenan como parte del objeto que se instancia en alguna parte . La forma más fácil de pensar dónde está esto es el montón. Sin embargo , este no es siempre el caso. Como se describe en la teoría y práctica de Java: Leyendas del rendimiento urbano, revisado :
Por lo tanto, más allá de decir "el objeto se crea y el campo también está allí", no se puede decir si hay algo en el montón o en la pila. Tenga en cuenta que para los objetos pequeños y de corta duración, es posible que el 'objeto' no exista en la memoria como tal y en su lugar puede tener sus campos colocados directamente en los registros.
El artículo concluye con:
Por lo tanto, si tiene un código similar al siguiente:
donde
...
no permitequx
salir de ese alcance,qux
puede asignarse en la pila en su lugar. En realidad, esto es una victoria para la máquina virtual porque significa que no es necesario que se recolecte basura, desaparecerá cuando salga del alcance.Más sobre análisis de escape en Wikipedia. Para aquellos dispuestos a profundizar en los documentos, Escape Analysis for Java de IBM. Para aquellos que vienen de un mundo de C #, pueden encontrar buenas lecturas de The Stack Is An Implementation Detail y The Truth About Value de Eric Lippert (son útiles para los tipos de Java, ya que muchos de los conceptos y aspectos son iguales o similares) . ¿Por qué los libros .Net hablan de la asignación de memoria de pila frente a pila? También entra en esto.
En los porqués de la pila y el montón
En el montón
Entonces, ¿por qué tener la pila o el montón? Para las cosas que dejan alcance, la pila puede ser costosa. Considera el código:
Los parámetros también son parte de la pila. En el caso de que no tenga un montón, estaría pasando el conjunto completo de valores en la pila. Esto está bien para
"foo"
cadenas pequeñas ... pero qué pasaría si alguien colocara un archivo XML enorme en esa cadena. Cada llamada copiaría toda la cadena enorme en la pila, y eso sería un desperdicio.En cambio, es mejor colocar los objetos que tienen algo de vida fuera del alcance inmediato (pasados a otro alcance, atrapados en una estructura que alguien más está manteniendo, etc.) en otra área que se llama el montón.
En la pila
No necesitas la pila. Uno podría, hipotéticamente, escribir un lenguaje que no use una pila (de profundidad arbitraria). Un viejo BASIC que aprendí en mi juventud lo hizo, uno solo podía hacer 8 niveles de
gosub
llamadas y todas las variables eran globales, no había pila.La ventaja de la pila es que cuando tiene una variable que existe con un ámbito, cuando abandona ese ámbito, se abre el marco de la pila. Realmente simplifica lo que hay y lo que no. El programa pasa a otro procedimiento, un nuevo marco de pila; el programa vuelve al procedimiento y usted vuelve al que ve su alcance actual; el programa deja el procedimiento y todos los elementos de la pila se desasignan.
Esto realmente facilita la vida de la persona que escribe el tiempo de ejecución para que el código use una pila y un montón. Simplemente tienen muchos conceptos y formas de trabajar en el código, lo que permite a la persona que escribe el código en el idioma liberarse de pensar explícitamente en ellos.
La naturaleza de la pila también significa que no puede fragmentarse. La fragmentación de la memoria es un problema real con el montón. Asigne algunos objetos, luego la basura recolecte uno del medio y luego intente encontrar espacio para asignar el siguiente grande. Es un desastre. Ser capaz de poner cosas en la pila significa que no tienes que lidiar con eso.
Cuando algo es basura recolectada
Cuando algo es basura recolectada, se va. Pero es solo basura recolectada porque ya se ha olvidado: no hay más referencias al objeto en el programa a las que se pueda acceder desde el estado actual del programa.
Señalaré que esta es una simplificación muy grande de la recolección de basura. Hay muchos recolectores de basura (incluso dentro de Java; puede ajustar el recolector de basura mediante el uso de varias banderas ( documentos ). Estos se comportan de manera diferente y los matices de cómo cada uno hace las cosas son demasiado profundos para esta respuesta. Es posible que desee leer Conceptos básicos de Java Garbage Collection para tener una mejor idea de cómo funciona algo de eso.
Dicho esto, si algo se asigna en la pila, no es basura recolectada como parte de
System.gc()
él, se desasigna cuando aparece el marco de la pila. Si hay algo en el montón y se hace referencia desde algo en la pila, no se recolectará basura en ese momento.¿Por qué importa esto?
En su mayor parte, su tradición. Los libros de texto escritos y las clases de compilación y la documentación de varios bits hacen un gran negocio sobre el montón y la pila.
Sin embargo, las máquinas virtuales de hoy (JVM y similares) han hecho todo lo posible para tratar de mantener esto oculto al programador. A menos que se esté quedando sin uno u otro y necesite saber por qué (en lugar de simplemente aumentar el espacio de almacenamiento de manera adecuada), no importa demasiado.
El objeto está en algún lugar y está en el lugar donde se puede acceder de forma correcta y rápida durante el tiempo adecuado que existe. Si está en la pila o en el montón, realmente no importa.
fuente
fuente
En el montón, a menos que Java asigne la instancia de clase en la pila como una optimización después de probar mediante análisis de escape que esto no afectará la semántica. Sin embargo, este es un detalle de implementación, por lo que para todos los fines prácticos, excepto la microoptimización, la respuesta está "en el montón".
La memoria de la pila debe asignarse y desasignarse en el último orden de salida. La memoria de montón se puede asignar y desasignar en cualquier orden.
Cuando el objeto es basura recolectada, no hay más referencias apuntando a él desde la pila. Si lo hubiera, mantendrían vivo el objeto. Las primitivas de pila no son basura recolectada porque se destruyen automáticamente cuando la función regresa.
fuente
La memoria de pila se usa para almacenar variables locales y llamadas a funciones.
Mientras que la memoria de almacenamiento dinámico se usa para almacenar objetos en Java. No importa, dónde se crea el objeto en el código.
En este caso, la primitiva a está asociada con un objeto de clase A. Por lo tanto, se crea en la memoria del montón.
Garbage Collector funciona bajo el alcance de la memoria del montón, por lo que destruye los objetos que no tienen una cadena de referencia desde la raíz.
fuente
Para una mejor comprensión (memoria de montón / pila):
fuente