Saltar al contenido

¿Qué es la fragmentación de la memoria?

Luego de de una prolongada recopilación de datos resolvimos este atasco que tienen ciertos los lectores. Te compartimos la respuesta y nuestro deseo es serte de gran apoyo.

Solución:

Imagine que tiene una extensión “grande” (32 bytes) de memoria libre:

----------------------------------
|                                |
----------------------------------

Ahora, asigne algo (5 asignaciones):

----------------------------------
|aaaabbccccccddeeee              |
----------------------------------

Ahora, libere las primeras cuatro asignaciones, pero no la quinta:

----------------------------------
|              eeee              |
----------------------------------

Ahora, intente asignar 16 bytes. Vaya, no puedo, aunque hay casi el doble gratis.

En sistemas con memoria virtual, la fragmentación es un problema menor de lo que podría pensar, porque las asignaciones grandes solo necesitan ser contiguas en virtual espacio de direcciones, no en físico espacio de dirección. Entonces, en mi ejemplo, si tuviera memoria virtual con un tamaño de página de 2 bytes, entonces podría hacer mi asignación de 16 bytes sin problemas. La memoria física se vería así:

----------------------------------
|ffffffffffffffeeeeff            |
----------------------------------

mientras que la memoria virtual (que es mucho más grande) podría verse así:

------------------------------------------------------...
|              eeeeffffffffffffffff                   
------------------------------------------------------...

El síntoma clásico de la fragmentación de la memoria es que intenta asignar un bloque grande y no puede, aunque parezca tener suficiente memoria libre. Otra posible consecuencia es la incapacidad del proceso para devolver la memoria al sistema operativo (debido a que cada uno de los bloques grandes que ha asignado desde el sistema operativo, por malloc etc. para subdividir, le queda algo, aunque la mayor parte de cada bloque ya no se utiliza).

Las tácticas para prevenir la fragmentación de la memoria en C ++ funcionan mediante la asignación de objetos de diferentes áreas según su tamaño y / o su vida útil esperada. Entonces, si va a crear muchos objetos y destruirlos todos juntos más tarde, asígnelos de un grupo de memoria. Cualquier otra asignación que haga entre ellos no será del grupo, por lo tanto, no se ubicará entre ellos en la memoria, por lo que la memoria no se fragmentará como resultado. O bien, si va a asignar muchos objetos del mismo tamaño, asígnelos del mismo grupo. Entonces, un tramo de espacio libre en la piscina nunca puede ser más pequeño que el tamaño que está tratando de asignar de esa piscina.

Por lo general, no necesita preocuparse mucho por ello, a menos que su programa sea de larga duración y realice muchas asignaciones y liberaciones. Es cuando tienes mezclas de objetos de corta y larga duración cuando estás en mayor riesgo, pero incluso entonces malloc hará todo lo posible para ayudar. Básicamente, ignórelo hasta que su programa tenga fallas de asignación o inesperadamente haga que el sistema se quede sin memoria (¡vea esto en las pruebas, de preferencia!).

Las bibliotecas estándar no son peores que cualquier otra cosa que asigne memoria, y todos los contenedores estándar tienen un Alloc parámetro de plantilla que puede utilizar para ajustar su estrategia de asignación si es absolutamente necesario.

¿Qué es la fragmentación de la memoria?

La fragmentación de la memoria se produce cuando la mayor parte de su memoria se asigna en una gran cantidad de bloques no contiguos o fragmentos, lo que deja un buen porcentaje de la memoria total sin asignar, pero inutilizable para la mayoría de los escenarios típicos. Esto da como resultado excepciones de memoria insuficiente o errores de asignación (es decir, malloc devuelve null).

La forma más fácil de pensar en esto es imaginar que tienes una gran pared vacía en la que necesitas poner fotos. de diferentes tamaños sobre. Cada imagen toma un tamaño determinado y, obviamente, no puede dividirla en partes más pequeñas para que encaje. Necesita un lugar vacío en la pared, del tamaño de la imagen, o de lo contrario no puede colocarlo. Ahora, si comienza a colgar cuadros en la pared y no tiene cuidado con la forma en que los coloca, pronto terminará con una pared que está parcialmente cubierta con cuadros y, aunque puede tener espacios vacíos, la mayoría de los cuadros nuevos no encajarán. porque son más grandes que los lugares disponibles. Aún puede colgar cuadros muy pequeños, pero la mayoría de ellos no encajarán. Así que tendrás que reorganizar (compactar) los que ya están en la pared para dejar espacio para más.

Ahora, imagina que la pared es tu (montón) memoria y las imágenes son objetos … Eso es fragmentación de la memoria …

¿Cómo puedo saber si la fragmentación de la memoria es un problema para mi aplicación? ¿Qué tipo de programa es más probable que sufra?

Una señal reveladora de que puede estar lidiando con la fragmentación de la memoria es si obtiene muchos errores de asignación, especialmente cuando el porcentaje de memoria utilizada es alto, pero aún no ha agotado toda la memoria, por lo que técnicamente debería tener mucho espacio. para los objetos que está intentando asignar.

Cuando la memoria está muy fragmentada, es probable que las asignaciones de memoria demoren más porque el asignador de memoria tiene que trabajar más para encontrar un espacio adecuado para el nuevo objeto. Si, a su vez, tiene muchas asignaciones de memoria (lo que probablemente tenga ya que terminó con la fragmentación de la memoria), el tiempo de asignación puede incluso causar retrasos notables.

¿Cuáles son las buenas formas comunes de lidiar con la fragmentación de la memoria?

Utilice un buen algoritmo para asignar memoria. En lugar de asignar memoria para una gran cantidad de objetos pequeños, preasigne memoria para un contiguo array de esos objetos más pequeños. A veces, desperdiciar un poco la asignación de memoria puede mejorar el rendimiento y puede ahorrarle la molestia de tener que lidiar con la fragmentación de la memoria.

La fragmentación de la memoria es el mismo concepto que la fragmentación del disco: se refiere al desperdicio de espacio porque las áreas en uso no están empaquetadas lo suficientemente juntas.

Suponga, para un ejemplo de juguete simple, que tiene diez bytes de memoria:

 |   |   |   |   |   |   |   |   |   |   |
   0   1   2   3   4   5   6   7   8   9

Ahora asignemos tres bloques de tres bytes, denominados A, B y C:

 | A | A | A | B | B | B | C | C | C |   |
   0   1   2   3   4   5   6   7   8   9

Ahora desasigne el bloque B:

 | A | A | A |   |   |   | C | C | C |   |
   0   1   2   3   4   5   6   7   8   9

Ahora, ¿qué sucede si intentamos asignar un bloque D de cuatro bytes? Bueno, tenemos cuatro bytes de memoria libres, pero no tenemos cuatro contiguo bytes de memoria libres, por lo que no podemos asignar D! Este es un uso ineficiente de la memoria, porque deberíamos haber podido almacenar D, pero no pudimos. Y no podemos mover C para hacer espacio, porque es muy probable que algunas variables de nuestro programa apunten a C y no podamos encontrar y cambiar automáticamente todos estos valores.

¿Cómo sabes que es un problema? Bueno, la señal más importante es que el tamaño de la memoria virtual de su programa es considerablemente mayor que la cantidad de memoria que está utilizando en realidad. En un ejemplo del mundo real, tendría más de diez bytes de memoria, por lo que D simplemente se asignaría comenzando un byte 9, y los bytes 3-5 permanecerían sin usar a menos que luego asignara algo de tres bytes de longitud o menos.

En este ejemplo, 3 bytes no es mucho para desperdiciar, pero considere un caso más patológico en el que dos asignaciones de un par de bytes están, por ejemplo, con diez megabytes de diferencia en la memoria, y necesita asignar un bloque de tamaño de 10 megabytes. + 1 byte. Tienes que pedirle al sistema operativo más de diez megabytes más de memoria virtual para hacer eso, aunque solo te falte un byte para tener suficiente espacio.

¿Cómo lo previene? Los peores casos tienden a surgir cuando crea y destruye con frecuencia objetos pequeños, ya que eso tiende a producir un efecto de “queso suizo” con muchos objetos pequeños separados por muchos agujeros pequeños, lo que hace imposible colocar objetos más grandes en esos agujeros. Cuando sepa que va a hacer esto, una estrategia efectiva es preasignar un gran bloque de memoria como un grupo para sus objetos pequeños, y luego administrar manualmente la creación de los objetos pequeños dentro de ese bloque, en lugar de permitir el asignador predeterminado lo maneja.

En general, cuantas menos asignaciones haga, es menos probable que la memoria se fragmente. Sin embargo, STL se ocupa de esto con bastante eficacia. Si tienes un string que está usando la totalidad de su asignación actual y le agrega un carácter, no simplemente se reasigna a su longitud actual más uno, dobles su longitud. Ésta es una variación de la estrategia de “reserva para asignaciones pequeñas frecuentes”. los string está tomando una gran parte de la memoria para poder manejar de manera eficiente los pequeños aumentos repetidos de tamaño sin tener que repetir pequeñas reasignaciones. De hecho, todos los contenedores STL hacen este tipo de cosas, por lo que, en general, no tendrá que preocuparse demasiado por la fragmentación causada por la reasignación automática de contenedores STL.

Aunque, por supuesto, los contenedores STL no agrupan la memoria Entre entre sí, por lo que si va a crear muchos contenedores pequeños (en lugar de unos pocos contenedores que cambian de tamaño con frecuencia), es posible que deba preocuparse por prevenir la fragmentación de la misma manera que lo haría con cualquier objeto pequeño creado con frecuencia, STL o no.

Comentarios y puntuaciones

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *