Red de conocimiento informático - Aprendizaje de programación - ¿Hay pérdidas y desbordamientos de memoria en Java?

¿Hay pérdidas y desbordamientos de memoria en Java?

Desbordamientos y pérdidas de memoria en JAVA:

Para toda la aplicación y el espacio de memoria JVM, no hay espacio adicional que pueda asignarse a nuevos objetos. Por tanto se produce un desbordamiento de memoria.

Pérdida de memoria:

Durante todo el ciclo de vida de la aplicación, un objeto continúa existiendo, ocupando cada vez más espacio de memoria, lo que eventualmente conduce a una pérdida de memoria de JVM.

Por ejemplo: aplicaciones de almacenamiento en caché, si no se establece un límite superior, la capacidad de la caché puede seguir creciendo.

Las referencias a colecciones estáticas, si la colección contiene un número ilimitado de objetos, también pueden crecer sin límite con el tiempo, provocando eventualmente una pérdida de memoria de JVM.

Pérdida de memoria significa que los objetos en la aplicación existen durante mucho tiempo y continúan creciendo, lo que eventualmente conduce a pérdidas de memoria.

Se refiere al crecimiento del tamaño de un objeto durante un largo período de tiempo después de su asignación.

El desbordamiento de memoria se refiere a un espacio asignado insuficiente para todos los objetos en toda la aplicación, lo que resulta en un desbordamiento de la memoria.

Pérdida de memoria

Una pérdida de memoria se produce cuando un programa no logra liberar memoria que ya no se utiliza debido a negligencia o error. Una pérdida de memoria no es la desaparición física de la memoria, sino un desperdicio de memoria causado por la aplicación que asigna una sección de memoria y luego pierde el control de la sección de memoria debido a errores de diseño. Los síntomas de una pérdida de memoria son similares a muchos otros problemas y, por lo general, solo pueden ser analizados por programadores que tengan acceso al código fuente del programa.

Sin embargo, muchas personas han llegado a describir cualquier aumento no deseado en el uso de memoria como una pérdida de memoria, aunque esta descripción no es estrictamente precisa.

En general, solemos referirnos a las pérdidas de memoria

como pérdidas de memoria del montón. La memoria del montón se refiere a la memoria asignada por el programa desde el montón, su tamaño puede ser arbitrario (el tamaño del bloque de memoria se puede determinar durante la ejecución del programa) y debe demostrarse que se libera cuando se usa. Las aplicaciones generalmente usan funciones como malloc, realloc y new para asignar un bloque de memoria del montón. Después de su uso, el programa debe ser responsable de llamar al correspondiente free o delete para liberar el bloque de memoria. >

no se puede volver a utilizar, decimos que este bloque de memoria está filtrado.

Las pérdidas de memoria se pueden dividir en 4 tipos:

1.

Pérdidas de memoria frecuentes. El código que causa una pérdida de memoria se ejecutará varias veces, lo que provocará que se pierda una gran cantidad de memoria cada vez que se ejecute.

2.

Pérdidas de memoria ocasionales. Código que pierde memoria solo bajo circunstancias u operaciones específicas. Frecuentes y esporádicas son relativas. En determinadas circunstancias, una pérdida de memoria ocasional puede convertirse en una pérdida de memoria frecuente. Por lo tanto, el entorno de prueba y los métodos de prueba son cruciales para detectar pérdidas de memoria.

3.

Pérdida de memoria única. El código con pérdidas de memoria solo se ejecuta una vez o, debido a fallas en el algoritmo, siempre hay una sola pérdida de memoria. Por ejemplo, la memoria se asigna en el constructor de una clase y no se libera en el destructor, por lo que la pérdida de memoria se produce sólo una vez.

4.

Pérdidas de memoria ocultas. Un programa asigna memoria continuamente mientras se ejecuta, pero no la libera hasta el final. Estrictamente hablando, aquí no hay pérdida de memoria porque el programa eventualmente liberará toda la memoria solicitada.

Pero para los programas de servidor que se ejecutan durante días, semanas o incluso meses, no liberar memoria a tiempo puede llevar a agotar toda la memoria del sistema. Por lo tanto, a este tipo de pérdida de memoria lo llamamos pérdida de memoria implícita.

En pocas palabras:

Una pérdida de memoria se produce cuando se olvida liberar la memoria que se ha utilizado, poniendo así en riesgo el siguiente uso.

El desbordamiento de la memoria significa que una cierta cantidad de espacio de memoria no puede acomodar todos los datos que deben almacenarse, lo que provoca un desbordamiento de los datos de la memoria.

Explica principalmente el concepto de memoria y pérdidas y desbordamientos de memoria de las siguientes partes, distingue pérdidas de memoria y desbordamientos de memoria; divide áreas de memoria y comprende el mecanismo de recuperación de GC, se centra en cómo monitorear y descubrir problemas de memoria; Además, analizar el problema también presenta cómo resolver el problema de la memoria.

Lo siguiente es el comienzo de este artículo:

Parte 1 Concepto

Como todos sabemos, la memoria Java es administrada por la propia máquina virtual Java. C, debe liberarse solo. En términos generales, la asignación de memoria de Java se divide en dos partes, una es el montón de datos y la otra es la pila. Cuando el programa se está ejecutando, el montón de datos generalmente se asigna y todas las variables temporales locales se colocan en él. El ciclo de vida está relacionado con el proceso.

Pero si el programador declara una variable estática, entonces se ejecutará directamente en la pila y el proceso la destruirá, no necesariamente la variable estática.

Además, para garantizar que la memoria de Java no se desborde, Java tiene un mecanismo de recolección de basura.

System.gc() es el mecanismo de recolección de basura, que jvm utiliza para liberar la memoria ocupada por objetos que ya no se usan.

El lenguaje Java no requiere que la JVM tenga un mecanismo de recolección de basura, ni especifica cómo funciona el mecanismo de recolección de basura. El propósito de la recolección de basura es eliminar objetos que ya no se utilizan. La recolección de basura determina si se recicla un objeto determinando si un objeto vivo hace referencia a él.

Además, el desbordamiento de memoria significa que cuando solicita asignar más memoria de máquina virtual Java de la que el sistema puede proporcionar y el sistema no puede satisfacer sus necesidades, se producirá un desbordamiento de memoria.

Pérdida de memoria significa que solicita al sistema que asigne memoria para su uso (agregarla), pero no la devuelve (elimina) después de su uso. Como resultado, el bloque de memoria que solicitó no puede. ya no se puede acceder

Problema, los bloques de memoria que se han asignado no se pueden volver a usar A medida que la memoria en el servidor continúa consumiéndose, cada vez hay más memoria inutilizable disponible y el sistema no puede asignarla. programas que lo necesitan. Al reasignarlo a un programa que lo necesita se produce una fuga.

A medida que avanza, el programa se quedará gradualmente sin memoria disponible y la memoria se desbordará.

Parte 2: Principios

Recolección de basura JAVA y segmentación de memoria

En la Especificación de la máquina virtual Java, se mencionan los siguientes tipos de espacios de memoria:

p>

◇ Pila: privada para cada hilo.

◇ Montón: compartido por todos los hilos.

◇ Área de métodos: es un poco como un "segmento de código de proceso", que almacena información reflejada de cada clase cargada, código de funciones de clase, constantes de tiempo de compilación, etc.

◇ El área del método es la misma que el "segmento de código de proceso".

◇ Pila de métodos nativos: se utiliza principalmente para código nativo que rara vez participa en JNI.

Mientras que Java usa memoria de montón, el montón de Java es un área de datos en tiempo de ejecución desde la cual las instancias de clase (objetos) asignan espacio. El montón de la máquina virtual Java (JVM) almacena todos los objetos creados por las aplicaciones en ejecución, y la "recolección de basura" también está relacionada principalmente con la memoria del montón (Heap). montón) relacionado.

El concepto de recolección de basura es el proceso mediante el cual la Máquina Virtual JAVA (JVM) recupera memoria para objetos a los que ya no se hace referencia. En términos generales, consideramos que el estado de un objeto al que se hace referencia está "vivo", mientras que el estado de un objeto que no se ha aplicado o cuyas propiedades de referencia no se pueden recuperar es "muerto". La recolección de basura es el proceso de liberar la memoria de objetos que se encuentran en un estado "muerto". Las reglas y algoritmos de recolección de basura se aplican dinámicamente a la aplicación mientras la aplicación se está ejecutando

y se recopilan automáticamente.

El recolector de basura de JVM adopta una estrategia de recolección intergeneracional, que escanea y recicla objetos de la generación más joven con una frecuencia más alta (llamada recolección menor), mientras que los objetos de verificación y de la generación anterior se recolectan con mucha menos frecuencia y se denominan colecciones menores.

Esto elimina la necesidad de verificar todos los objetos en la memoria cada vez que se realiza la GC, y esta estrategia facilita la observación y el reciclaje en tiempo real.

(Sun JVM 1.3)

Hay dos tipos básicos de recopilación de memoria: uno se llama copiar o borrar, que mueve todos los objetos que aún están vivos a otro bloque de memoria. Luego, todo el bloque de memoria. El bloque de memoria se puede reciclar. Este método es eficaz, pero requiere una cierta cantidad de memoria libre y tiene una sobrecarga de copia. Este método se utiliza para colecciones secundarias

. Otro método, llamado mark-compact, marca objetos vivos y los reubica juntos para formar un gran bloque de memoria para que se pueda recuperar el resto de la memoria. Este método no ocupa espacio adicional, pero es relativamente lento (este método se utiliza para las colecciones principales).

)

Algunos objetos tienen ciclos de vida cortos, como iteradores y variables locales. Otros objetos se crean con vidas más largas, como los objetos persistentes.

La estrategia de generación del recolector de basura es dividir el área de memoria en varias generaciones y luego asignar uno o más bloques de memoria a cada generación. Cuando una de las generaciones agota la memoria asignada, la JVM realizará una operación de GC local (también llamada colección menor) en el área de memoria asignada para recuperar los objetos ocupados por el estado de memoria "muerta". La GC local suele ser mucho más rápida que la GC completa.

La JVM define dos generaciones, la generación joven (a veces llamada "guardería") y la generación anterior. La generación más joven está formada por

"Eden Space" y dos "Survivor Spaces". Cuando se inicializa la memoria virtual, todos los objetos se asignan al espacio Eden y la mayoría de los objetos se liberan en esta área. Al realizar una GC menor, la máquina virtual mueve los objetos restantes inéditos del espacio Eden a uno de los espacios de supervivencia. Además, la máquina virtual moverá los objetos que han estado en el espacio superviviente durante mucho tiempo al espacio "retenido" de la generación anterior. Cuando se llena el espacio de generación "titular", se generará un GC completo, que es un proceso relativamente lento porque contiene todos los objetos vivos.

Puede comprender aproximadamente la división de generaciones en la siguiente figura:

Resumen de la tercera parte

El desbordamiento de memoria se debe principalmente a una aplicación irrazonable al escribir código Ciertos métodos y clases no se utilizaron, o no se esperaba que los objetos temporales ocuparan una gran cantidad de memoria, o se colocaron demasiados datos en la caché de JVM, o la presión de rendimiento provocó la acumulación de mensajes y. memoria ocupada, lo que provoca que la prueba de rendimiento falle, se genera una gran cantidad de objetos temporales y el GC no realiza una recuperación efectiva, o incluso no puede recuperarse en absoluto, lo que resulta en espacio de memoria insuficiente y desbordamiento de memoria.

Si se estima el uso de la memoria antes de la codificación y se evalúan los datos colocados en la memoria para garantizar que la información útil se libere lo antes posible y que el GC pueda recuperar la información inútil, entonces se puede hacer para hasta cierto punto para evitar problemas de desbordamiento de memoria.