1. Modelo de memoria Java
Al ejecutar un programa, la máquina virtual Java divide la memoria que administra en varias áreas de datos. La distribución de estas áreas de datos se muestra en la figura a continuación:
Contador de programa: un área de memoria pequeña que apunta al bytecode ejecutado actualmente. Si el hilo está ejecutando un método Java, este contador registra la dirección de la instrucción de Bytecode de la máquina virtual que se está ejecutando. Si el método nativo se ejecuta, el valor de la calculadora está vacío.
Java Virtual Machine Pila: los hilos son privados, y su ciclo de vida es consistente con los hilos. Cuando se ejecuta cada método, se creará una trama para almacenar información, como tablas variables locales, pilas de operandos, enlaces dinámicos, salidas de método, etc.
Pila de métodos locales: las funciones son similares a la pila de máquinas virtuales, excepto que la pila de máquinas virtuales realiza servicios de método Java para la máquina virtual, mientras que la pila de métodos locales sirve el método nativo utilizado.
Java Heap: es la pieza más grande de memoria de administración de máquinas virtuales, compartida por todos los hilos, esta área se usa para almacenar instancias de objetos y casi todos los objetos se asignan en esta área. El montón Java es el área principal del reciclaje de memoria. Desde la perspectiva del reciclaje de memoria, ya que la mayoría de los coleccionistas actuales usan algoritmos de recolección generacionales, el montón Java también se puede subdividir en: la nueva generación y la generación anterior. Si se subdivide un poco, se puede dividir en el espacio del Edén, desde el espacio de sobrevivientes, hasta el espacio de sobrevivientes, etc. Según la especificación de la máquina virtual Java, el montón Java puede estar en un espacio físicamente discontinuo, siempre que sea lógicamente continuo.
Área de método: al igual que Java, es compartido por varios subprocesos y se utiliza para almacenar datos, como información de clase que ha sido cargada por la máquina virtual, siempre encendida, variables estáticas, código compilado por el compilador instantáneo.
Piscina constante de tiempo de ejecución, Runtime Constant Pool es parte del área del método. Además de la versión de clase, los campos, los métodos, las interfaces y otra información de descripción, también hay un grupo constante en el archivo de clase, que se utiliza para almacenar varias referencias literales y simbólicas generadas durante el período de compilación. Durante el tiempo de ejecución, se pueden colocar nuevas constantes en la piscina constante. El más comúnmente utilizado es el método Intern () de la clase de cadena. Cuando una instancia de cadena llama a Intern, Java encuentra si hay las mismas constantes de cadena Unicode en el grupo constante. Si lo hay, devuelve su referencia; Si no, agregue un unicode igual a la cadena de instancia y devuelve su referencia.
2. Cómo determinar el objeto de basura
Hay varias instancias de objetos almacenadas en el montón de Java. Antes de que el recolector de basura recicle el montón, primero debe determinar qué objetos aún están "vivos" y cuáles tienen objetos "muertos", es decir, objetos que no se utilizarán de ninguna manera.
Conteo de citas
El método de conteo de citas es fácil de implementar y eficientemente, y es un buen algoritmo en la mayoría de los casos. El principio es: agregar un contador de referencia al objeto. Cada vez que hay un lugar para hacer referencia al objeto, el contador aumenta en 1. Cuando la referencia falla, el contador se reduce en 1. Cuando el valor del contador es 0, significa que el objeto ya no se usa. Cabe señalar que el método de conteo de referencia es difícil de resolver el problema de la referencia mutua entre los objetos, y las máquinas virtuales Java convencionales no utilizan el método de conteo de referencia para administrar la memoria.
Algoritmo de análisis de accesibilidad
La idea básica de este algoritmo es buscar hacia abajo a través de una serie de objetos llamados "Roots GC" como punto de partida, comenzando desde estos nodos. La ruta buscada se llama cadena de referencia. Cuando un objeto no está conectado a las raíces de GC sin ninguna cadena de referencia (en las palabras de la teoría de gráficos, es de las raíces GC a este objeto que no es lo que no se puede presentar), se demuestra que este objeto no está disponible. Como se muestra en la figura, aunque los objetos 5, el objeto 6 y el objeto 7 están relacionados entre sí, no pueden existir con las raíces GC, por lo que se considerará objetos reciclables.
En el lenguaje Java, los siguientes objetos que se pueden usar como raíces GC incluyen:
Objeto referenciado en la pila de máquinas virtuales (tabla de variables locales en el marco de pila).
Objeto referenciado por el atributo estático de la clase en el área de método.
Objeto a la que se hace referencia por constantes en el área del método.
Objetos referenciados por JNI (es decir, el método nativo general) en la pila del método local.
Ahora la pregunta es, ¿tendrá el algoritmo de análisis de accesibilidad un problema de referencia circular entre los objetos? La respuesta es sí, es decir, no habrá ningún problema de referencia circular entre objetos. GC Root es un "punto de partida" especialmente definido fuera del gráfico de objeto y no puede ser referenciado por objetos en el gráfico de objetos.
Morir o no morir
Incluso los objetos inalcanzables en el algoritmo de análisis de accesibilidad no son "deben morir". En este momento, están temporalmente en la etapa de "libertad condicional". Para declarar realmente un objeto muerto, debe pasar por al menos dos procesos de marcado: si el objeto encuentra que no hay una cadena de referencia conectada a las raíces GC después de realizar el análisis de accesibilidad, se marcará por primera vez y se filtrará. La condición de filtrado es si es necesario que este objeto ejecute el método finapze (). Cuando el objeto no sobrescribe el método Finapze (), o el método finapze () ha sido llamado por la máquina virtual, la máquina virtual considera que ambos casos "no es necesario ejecutar". En el programa, puede sobrescribir Finapze () para crear un proceso de autoalvatación "emocionante", pero esta es solo una oportunidad.
/** * Este código demuestra dos puntos: * 1. Los objetos pueden salvarse cuando son GC. * 2. Solo hay una posibilidad de auto-rescate, porque el método finapze () de un objeto solo será llamado automáticamente una vez por el sistema como máximo * @author zzm */ pubpc class finapzeescapegc {Pubpc estático finapzeescapeGC save_hook = null; PUBPC void isapve () {System.out.println ("Sí, todavía soy apve :)"); } @Override protegido void finapze () lanza lanzable {super.finapze (); System.out.println ("Finapze Mehtod ejecutado!"); Finapzeescapegc.save_hook = this; } PUBPC static void main (string [] args) lanza lando {save_hook = new FinapzeSescapeGC (); // El objeto se guarda con éxito por primera vez save_hook = null; System.gc (); // Debido a que el método de Finapze tiene baja prioridad, haga una pausa durante 0.5 segundos para esperar a su hilo. Sleep (500); if (save_hook! = null) {save_hook.isapve (); } else {System.out.println ("No, estoy muerto :(");} // El siguiente código es exactamente el mismo que el anterior, pero esta vez el auto-rescate falló. Save_hook = null; system.gc (); // porque el método Finapze tiene una prioridad baja, detiene 0.5 segundos para esperar a que threat.sleep (500); if ((save_hhook). Save_hook.isapve ();El resultado de la ejecución es:
Finapze Mehtod ejecutado! Sí, todavía soy una idea :) No, estoy muerto :(
Hablemos de citas
Si está juzgando el número de referencias de un objeto a través de un algoritmo de conteo de referencia o determinar si la cadena de referencia del objeto es accesible a través de un algoritmo de análisis de accesibilidad, determinando si la supervivencia del objeto está relacionada con la "referencia". Antes de JDK 1.2, la definición de referencias en Java era muy tradicional: si el valor almacenado en los datos de tipo de referencia representa la dirección inicial de otra memoria, se dice que esta memoria representa una referencia. Después de JDK 1.2, Java amplió el concepto de referencia y dividió las referencias en cuatro tipos: referencia fuerte, referencia suave, referencia débil y referencia fantasma. La fuerza de estos cuatro tipos de referencia se debilitó gradualmente a su vez.
• La cita fuerte se refiere a referencias que son comunes en el código del programa, como "Obj OBJ = New Object ()". Mientras la fuerte cita todavía exista, el recolector de basura nunca reciclará el objeto referenciado.
• Las referencias suaves se utilizan para describir algunos objetos útiles pero no necesarios. Para objetos asociados con referencia suave, estos objetos se enumerarán en el alcance de reciclaje para un segundo reciclaje antes de que el sistema esté a punto de tener una excepción de desbordamiento de memoria. Si no hay suficiente memoria para este reciclaje, se lanzará una excepción de desbordamiento de memoria. Después de JDK 1.2, se proporciona la clase Softreference para implementar referencias suaves.
• Las referencias débiles también se usan para describir objetos no esenciales, pero su fuerza es más débil que las referencias suaves. Los objetos asociados con referencias débiles solo pueden sobrevivir hasta que ocurra la próxima recolección de basura. Cuando funciona el recolector de basura, los objetos que solo están asociados con referencias débiles se recolectan independientemente de si la memoria actual es suficiente. Después de JDK 1.2, se proporciona la clase WeakReference para implementar referencias débiles.
• Las citas naciones también se llaman citas fantasmas o citas fantasmas, y son la relación de cita más débil. Si un objeto tiene una referencia virtual no tendrá ningún impacto en su tiempo de supervivencia, ni será posible obtener una instancia de objeto a través de la referencia virtual. El único propósito de configurar asociaciones de referencia virtual para un objeto es recibir una notificación del sistema cuando el coleccionista recicla el objeto. Después de JDK 1.2, la clase Phantomreference se proporciona para implementar referencias virtuales.
Ejemplo de uso de referencia suave:
paquete jvm; import java.lang.ref.softreference; class node {PUBPC String msg = "";} PUBPC Class Hello {PUBPC static void main (string [] args) {nodo nodo1 = new node (); // sólido nodo de referencia1.msg = "nodo1"; softreference <node> node2 = new Softreference <Node> (nodo1); // referencia suave node2.get (). Msg = "node2"; system.out.println (node1.msg); system.out.println (node2.get (). Msg);}}El resultado de la salida es:
nodo2node2
3. Algoritmo típico de recolección de basura
1. Algoritmo de mark-sweep (Mark-Clar)
Este es el algoritmo de recolección de basura más básico. La razón por la que se dice que es la más básica es que es la más fácil de implementar y la idea más simple. El algoritmo de limpieza de marcas se divide en dos etapas: la etapa de marcado y la etapa de limpieza. La tarea de la etapa de marcado es marcar todos los objetos que necesitan ser reciclados, y la etapa de compensación es reciclar el espacio ocupado por los objetos marcados. El proceso específico se muestra en la figura a continuación:
Se puede ver fácilmente en la figura que el algoritmo de limpieza de marcas es más fácil de implementar, pero existe un problema grave de que es fácil generar fragmentos de memoria. Demasiados fragmentos pueden causar la incapacidad de encontrar suficiente espacio al asignar espacio para objetos grandes en el proceso posterior, y activar una nueva acción de recolección de basura de antemano.
2. Algoritmo de copia
Para resolver las deficiencias del algoritmo Mark-Sweep, se propuso el algoritmo de copia. Divide la memoria disponible en dos piezas de igual tamaño por capacidad, usando solo una pieza a la vez. Cuando se use esta memoria, copie el objeto de vida muerto a otra pieza y luego limpie el espacio de memoria usado a la vez, para que los problemas de fragmentación de memoria no ocurran. El proceso específico se muestra en la figura a continuación:
Aunque este algoritmo es fácil de implementar, eficiente para ejecutar y no es fácil de generar fragmentación de memoria, es costoso usar el espacio de memoria porque la memoria que se puede usar se reduce a la mitad de la original.
Obviamente, la eficiencia del algoritmo de copia tiene mucho que ver con el número de objetos sobrevivientes. Si hay muchos objetos sobrevivientes, la eficiencia del algoritmo de copia se reducirá considerablemente.
3. Algoritmo de marca (marca de marca)
Para resolver las deficiencias del algoritmo de copia y hacer uso completo del espacio de memoria, se propone el algoritmo de marca compacto. El algoritmo marca lo mismo que Mark-Sweep, pero después de completar la marca, no limpia directamente los objetos reciclables, sino que mueve todos los objetos vivos a un extremo y luego limpia la memoria fuera del límite final. El proceso específico se muestra en la figura a continuación:
4. Algoritmo de colección generacional
El algoritmo de recolección de generación es actualmente utilizado por la mayoría de los recolectores de basura JVM. Su idea central es dividir la memoria en varias regiones diferentes de acuerdo con el ciclo de vida de la supervivencia del objeto. En términos generales, el área del montón se divide en la antigua generación y la generación joven. La característica de la antigua generación es que solo un pequeño número de objetos necesita reciclarse cada vez que se recolecte la basura, mientras que la característica de la nueva generación es que una gran cantidad de objetos deben reciclar cada vez que se recolecte la basura. Luego, el algoritmo de recolección más adecuado se puede adoptar de acuerdo con las características de diferentes generaciones.
En la actualidad, la mayoría de los recolectores de basura adoptan el algoritmo de copia para la nueva generación, porque en la nueva generación, la mayoría de los objetos deben reciclar cada vez, es decir, el número de operaciones que deben copiarse es pequeño, pero en realidad, el espacio de la nueva generación no se divide de acuerdo con una relación de 1: 1. En términos generales, la nueva generación se divide en un espacio de Edén más grande y dos espacios de sobrevivientes más pequeños (generalmente 8: 1: 1). Cada vez que se usan el espacio Eden y uno de los espacios de sobrevivientes, al reciclar, los objetos que aún sobreviven en Edén y Survivor se copian a otro espacio de sobrevivientes, y luego se limpian Eden y los espacios de sobrevivientes que acaban de usar.
Debido a que la vejez es que solo un pequeño número de objetos se reciclan cada vez, el algoritmo de marca compacto generalmente se usa.
El breve análisis anterior del modelo de memoria Java y la recolección de basura es todo el contenido que comparto con usted. Espero que pueda darle una referencia y espero que pueda apoyar más a Wulin.com.