Gestión de memoria (V)

Fragmentación del free store


En la mayoría de los compiladores del lenguaje C++, el alojamiento dinámico en el espacio de almacenamiento libre (mediante expresiones newdelete) suele venir implementado en torno a las funciones malloc() y free() propias del lenguaje C. Por cada nueva petición de almacenamiento, el sistema debe realizar una búsqueda efectiva de un bloque en memoria sin utilizar de un tamaño igual o superior al solicitado. De no existir suficiente espacio en memoria, se notifica el error emitiendo por defecto una excepción de tipo std::bad_alloc. Existen múltiples algoritmos de alojamiento posibles, cada uno de los cuales posee sus ventajas y sus inconvenientes en relación a su eficiencia en la búsqueda y uso de la memoria [1,2].

Con el fin de entender el modo en que el free store se fragmenta tras un uso continuado de expresiones new/delete y los problemas que esto conlleva [3], consideremos un segmento de memoria virtual de tan sólo 12 KiB de tamaño. En un inicio, el bloque de memoria se encuentra inutilizado (véase la Figura 1 más abajo). Supongamos que se realizan secuencialmente las operaciones de alojamiento de tres objetos de 4 KiB de tamaño, respectivamente (Figura 2) y, posteriormente, el desalojo del primer y último objeto, tal y como muestra la Figura 3. La memoria ha quedado, como se ve, fragmentada. De hecho, de requerirse a continuación un alojamiento adicional de 8 KiB de memoria, se produciría la emisión de una excepción informando de la imposibilidad de dicha operación. En efecto, aun cuando existan un total de 8 KiB libres en memoria, no es posible alojarlos de manera contigua.


Esto es así incluso al trabajar con memoria virtual, pues como programadores solemos requerir el uso de bloques continuos de direcciones en memoria, no bloques continuos en memoria física [4].

Un buen diseño de la aplicación resulta crítico a la hora de mitigar la fragmentación de la memoria. Así, por ejemplo, si una operación que vaya a repetirse múltiples veces en tiempo de ejecución requiriese la creación de un búfer de tamaño conocido, es claro que el desarrollador debería alojar la memoria una única vez, procediendo a su reutilización cuantas veces sea necesario, y no permitir que el búfer sea alojado y desalojado cada vez que éste tenga que ser utilizado.


Referencias bibliográficas:
  1. Knuth, D. E., 'The Art of Computer Programming', Vol. 1. Addison-Wesley (1998).
  2. Alexandrescu A., 'Modern C++ Design'. Addison-Wesley (2001).
  3. Dickheiser M. J., 'C++ for Game Programmers', Second Edition. Charles River Media (2006).
  4. Dynamic memory allocation and virtual memory - https://www.cprogramming.com/tutorial/virtual_memory_and_heaps.html
  5. MSDN blogs - https://blogs.msdn.microsoft.com/david.wang/2006/02/15/more-on-virtual-memory-memory-fragmentation-and-leaks-and-wow64/
  6. Stackoverflow - https://stackoverflow.com/questions/3770457/what-is-memory-fragmentation

1 comentario:

  1. Muchas gracias Daniel, excelente secuencia de articulos, se aprende bastante

    ResponderEliminar