logo

Gestión de memoria en Java

En Java, la gestión de la memoria es el proceso de asignación y desasignación de objetos, denominado gestión de la memoria. Java realiza la gestión de la memoria automáticamente. Java utiliza un sistema automático de gestión de memoria llamado recolector de basura . Por lo tanto, no estamos obligados a implementar lógica de gestión de memoria en nuestra aplicación. La gestión de la memoria Java se divide en dos partes principales:

ubuntu que comando
    Estructura de memoria JVM Trabajo del recolector de basura.

Estructura de memoria JVM

JVM crea varias áreas de datos en tiempo de ejecución en un montón. Estas áreas se utilizan durante la ejecución del programa. Las áreas de memoria se destruyen cuando sale la JVM, mientras que las áreas de datos se destruyen cuando sale el subproceso.

Gestión de memoria en Java

Área del método

El área de método es parte de la memoria del montón que se comparte entre todos los subprocesos. Se crea cuando se inicia la JVM. Se utiliza para almacenar la estructura de clases, el nombre de la superclase, el nombre de la interfaz y los constructores. La JVM almacena los siguientes tipos de información en el área de métodos:

  • Un nombre completo de un tipo (por ejemplo, cadena)
  • Los modificadores del tipo.
  • Nombre de superclase directa del tipo
  • Una lista estructurada de los nombres completos de superinterfaces.

Área del montón

El montón almacena los objetos reales. Se crea cuando se inicia la JVM. El usuario puede controlar el montón si es necesario. Puede ser de tamaño fijo o dinámico. Cuando utiliza una nueva palabra clave, la JVM crea una instancia para el objeto en un montón. Mientras que la referencia de ese objeto se almacena en la pila. Sólo existe un montón para cada proceso JVM en ejecución. Cuando el montón se llena, se recoge la basura. Por ejemplo:

 StringBuilder sb= new StringBuilder(); 

La declaración anterior crea un objeto de la clase StringBuilder. El objeto se asigna al montón y la referencia sb se asigna a la pila. El montón se divide en las siguientes partes:

  • Generación joven
  • Espacio de supervivientes
  • vieja generacion
  • Generación permanente
  • Caché de código

Tipo de referencia

Hay cuatro tipos de referencias: Fuerte , Débil , Suave , y Referencia fantasma . La diferencia entre los tipos de referencias es que los objetos en el montón al que hacen referencia son elegibles para la recolección de basura según diferentes criterios.

Referencia fuerte: Es muy sencillo tal y como lo utilizamos en nuestra programación diaria. Cualquier objeto que tenga una referencia fuerte adjunta no es elegible para la recolección de basura. Podemos crear una referencia sólida utilizando la siguiente declaración:

 StringBuilder sb= new StringBuilder(); 

Referencia débil: No sobrevive después del siguiente proceso de recolección de basura. Si no estamos seguros de cuándo se volverán a solicitar los datos. En esta condición, podemos crear una referencia débil al mismo. En caso de que el recolector de basura lo procese, destruirá el objeto. Cuando volvemos a intentar recuperar ese objeto, obtenemos un valor nulo. Se define en java.lang.ref.WeakReference clase. Podemos crear una referencia débil usando la siguiente declaración:

 WeakReference reference = new WeakReference(new StringBuilder()); 

Referencia suave: Se recopila cuando la aplicación se está quedando sin memoria. El recolector de basura no recoge los objetos a los que se puede acceder fácilmente. Todos los objetos a los que se hace referencia suave se recopilan antes de que genere un OutOfMemoryError. Podemos crear una referencia suave usando la siguiente declaración:

 SoftReference reference = new SoftReference(new StringBuilder()); 

Referencia fantasma: Esta disponible en java.lang.ref paquete. Se define en java.lang.ref.PhantomReferencia clase. El objeto que solo tiene una referencia fantasma que lo señala se puede recolectar cuando el recolector de basura quiera recolectarlo. Podemos crear una referencia fantasma usando la siguiente declaración:

 PhantomReference reference = new PhantomReference(new StringBuilder()); 

Área de pila

El área de pila se genera cuando se crea un hilo. Puede ser de tamaño fijo o dinámico. La memoria de la pila se asigna por subproceso. Se utiliza para almacenar datos y resultados parciales. Contiene referencias a objetos del montón. También contiene el valor en sí en lugar de una referencia a un objeto del montón. Las variables que se almacenan en la pila tienen cierta visibilidad, llamada alcance.

Marco de pila: El marco de pila es una estructura de datos que contiene los datos del hilo. Los datos del hilo representan el estado del hilo en el método actual.

  • Se utiliza para almacenar resultados y datos parciales. También realiza enlaces dinámicos, valores devueltos por métodos y excepciones de envío.
  • Cuando se invoca un método, se crea un nuevo marco. Destruye el marco cuando se completa la invocación del método.
  • Cada cuadro contiene su propia matriz de variables locales (LVA), pila de operandos (OS) y datos de cuadro (FD).
  • Los tamaños de LVA, OS y FD se determinan en el momento de la compilación.
  • Sólo un marco (el marco para ejecutar el método) está activo en cualquier punto de un hilo de control determinado. Este fotograma se denomina fotograma actual y su método se conoce como método actual. La clase de método se llama clase actual.
  • El marco detiene el método actual, si su método invoca otro método o si el método se completa.
  • El marco creado por un hilo es local para ese hilo y ningún otro hilo puede hacer referencia a él.

Pila de métodos nativos

También se le conoce como pila C. Es una pila de código nativo escrito en un lenguaje distinto de Java. Java Native Interface (JNI) llama a la pila nativa. El rendimiento de la pila nativa depende del sistema operativo.

Registros de PC

Cada hilo tiene un registro de contador de programa (PC) asociado. El registro de PC almacena la dirección del remitente o un puntero nativo. También contiene la dirección de las instrucciones JVM que se están ejecutando actualmente.

Trabajo del recolector de basura.

Descripción general del recolector de basura

Cuando un programa se ejecuta en Java, utiliza la memoria de diferentes maneras. El montón es una parte de la memoria donde viven los objetos. Es la única parte de la memoria que participa en el proceso de recolección de basura. También se le conoce como montón de basura recolectable. Toda la recolección de basura garantiza que el montón tenga la mayor cantidad de espacio libre posible. La función del recolector de basura es encontrar y eliminar los objetos a los que no se puede acceder.

Asignación de objetos

Cuando se asigna un objeto, JRockit JVM verifica el tamaño del objeto. Distingue entre objetos pequeños y grandes. El tamaño pequeño y grande depende de la versión de JVM, el tamaño del montón, la estrategia de recolección de basura y la plataforma utilizada. El tamaño de un objeto suele estar entre 2 y 128 KB.

Los objetos pequeños se almacenan en el área local de subprocesos (TLA), que es una parte libre del montón. TLA no se sincroniza con otros subprocesos. Cuando el TLA se llena, solicita un nuevo TLA.

Por otro lado, los objetos grandes que no caben dentro del TLA se asignan directamente al montón. Si un hilo utiliza el espacio joven, se almacena directamente en el espacio antiguo. El objeto grande requiere más sincronización entre los subprocesos.

¿Qué hace el recolector de basura Java?

JVM controla el recolector de basura. JVM decide cuándo realizar la recolección de basura. También podemos solicitar a la JVM que ejecute el recolector de basura. Pero no hay garantía bajo ninguna condición de que la JVM cumpla. JVM ejecuta el recolector de basura si detecta que la memoria se está agotando. Cuando un programa Java solicita el recolector de basura, la JVM generalmente concede la solicitud en poco tiempo. No se asegura de que las solicitudes sean aceptadas.

El punto a entender es que ' ¿Cuándo un objeto se vuelve elegible para la recolección de basura? '

Cada programa Java tiene más de un hilo. Cada hilo tiene su pila de ejecución. Hay un hilo para ejecutar en el programa Java que es un método main(). Ahora podemos decir que un objeto es elegible para la recolección de basura cuando ningún hilo activo puede acceder a él. El recolector de basura considera que ese objeto es elegible para su eliminación. Si un programa tiene una variable de referencia que hace referencia a un objeto, esa variable de referencia está disponible para el hilo vivo, este objeto se llama accesible .

Aquí surge una pregunta que ' ¿Puede una aplicación Java quedarse sin memoria? '

La respuesta es sí. El sistema de recolección de basura intenta extraer objetos de la memoria cuando no están en uso. Sin embargo, si mantiene muchos objetos activos, la recolección de basura no garantiza que haya suficiente memoria. Sólo la memoria disponible se gestionará de forma eficaz.

Tipos de recolección de basura

Hay cinco tipos de recolección de basura que son los siguientes:

    GC en serie:Utiliza el enfoque de marca y barrido para generaciones jóvenes y mayores, que es GC menor y mayor.GC paralelo:Es similar al GC en serie, excepto que genera N (el número de núcleos de CPU en el sistema) subprocesos para la recolección de basura de la generación joven.GC antiguo paralelo:Es similar al GC paralelo, excepto que utiliza múltiples subprocesos para ambas generaciones.Recopilador de barrido de marcas concurrente (CMS):Realiza la recolección de basura para la generación anterior. Puede limitar la cantidad de subprocesos en el recopilador CMS usando XX:ParalleCMSThreads=opción JVM . También se le conoce como recopilador simultáneo de pausa baja.Recolector de basura G1:Se introdujo en Java 7. Su objetivo es reemplazar el recopilador CMS. Es un recopilador CMS, paralelo y concurrente. No hay espacio para las generaciones jóvenes y mayores. Divide el montón en varios montones del mismo tamaño. Primero recopila las regiones con menos datos en vivo.

Algoritmo de marca y barrido

JRockit JVM utiliza el algoritmo de marca y barrido para realizar la recolección de basura. Contiene dos fases, la fase de marca y la fase de barrido.

Fase de marca: Los objetos a los que se puede acceder desde subprocesos, identificadores nativos y otras fuentes raíz de GC se marcan como activos. Cada árbol de objetos tiene más de un objeto raíz. La raíz de GC siempre es accesible. Entonces, cualquier objeto que tenga una raíz de recolección de basura en su raíz. Identifica y marca todos los objetos que están en uso, y el resto puede considerarse basura.

Gestión de memoria en Java

Fase de barrido: En esta fase, se recorre el montón para encontrar el espacio entre los objetos vivos. Estos huecos se registran en la lista libre y están disponibles para la asignación de nuevos objetos.

Hay dos versiones mejoradas de marcar y barrer:

    Marcado y barrido simultáneos Marcado y barrido paralelo

Marcado y barrido simultáneos

Permite que los subprocesos continúen ejecutándose durante una gran parte de la recolección de basura. Existen los siguientes tipos de marcado:

    Marcado inicial:Identifica el conjunto raíz de objetos vivos. Se realiza mientras los hilos están en pausa.Marcado concurrente:En esta marcación se siguen las referencias del conjunto raíz. Encuentra y marca el resto de objetos vivos en un montón. Se hace mientras el hilo está en ejecución.Marcado previo a la limpieza:Identifica los cambios realizados mediante marcado concurrente. Otros objetos vivos marcados y encontrados. Se hace mientras los hilos se están ejecutando.Calificación final:Identifica los cambios realizados mediante marcado previo a la limpieza. Otros objetos vivos marcados y encontrados. Se realiza mientras los hilos están en pausa.

Marcado y barrido paralelo

Utiliza toda la CPU disponible en el sistema para realizar la recolección de basura lo más rápido posible. También se le llama recolector de basura paralelo. Los subprocesos no se ejecutan cuando se ejecuta la recolección de basura paralela.

Ventajas de marcar y barrer

  • Es un proceso recurrente.
  • Es un bucle infinito.
  • No se permiten gastos generales adicionales durante la ejecución de un algoritmo.

Contras de marcar y barrer

  • Detiene la ejecución normal del programa mientras se ejecuta el algoritmo de recolección de basura.
  • Se ejecuta varias veces en un programa.