simulador paginacion memoria gestion ejercicios ejemplos asignacion c++ windows optimization memory-management

c++ - gestion - paginacion de memoria ejemplos



Gestión de memoria en la aplicación intensiva de memoria (9)

¿optas por escribir tu propio administrador de memoria personalizado para asignar memoria desde el espacio de direcciones virtuales o permites que CRT tome el control y haga la gestión de la memoria por ti?

La biblioteca estándar a menudo es lo suficientemente buena. Si no es así, en lugar de reemplazarlo, un paso más pequeño es anular el operator new y operator delete para clases específicas, no para todas las clases.

Si está desarrollando una aplicación de memoria intensiva en C ++ en Windows, ¿opta por escribir su propio administrador de memoria personalizado para asignar memoria desde el espacio de direcciones virtuales o permite que CRT tome el control y haga la gestión de la memoria por usted? Estoy especialmente preocupado por la fragmentación causada por la asignación y la desasignación de objetos pequeños en el montón. Debido a esto, creo que el proceso se quedará sin memoria aunque haya suficiente memoria pero esté fragmentado.


¿Fue SmartHeap de MicroQuill?


Creo que su mejor opción es no implementar uno hasta que los perfiles demuestren que el CRT está fragmentando la memoria de una manera que daña el rendimiento de su aplicación. Los chicos de CRT, core OS y STL pasan mucho tiempo pensando en la administración de la memoria.

Existe una buena posibilidad de que su código funcione bastante bien en los asignadores existentes sin necesidad de cambios. Ciertamente hay una mejor posibilidad de eso, que hay uno que obtiene un asignador de memoria la primera vez. He escrito asignadores de memoria antes para circunstancias similares y es una tarea monstruosa para asumir. No es tan sorprendente que la versión que heredé estuvo plagada de problemas de fragmentación.

La otra ventaja de esperar hasta que un perfil muestre que es un problema es que también sabrá si realmente ha arreglado algo. Esa es la parte más importante de una solución de rendimiento.

Siempre que utilice las clases de recopilación estándar y algoritmos (como STL / BOOST) no debería ser muy difícil conectar un nuevo asignador más adelante en el ciclo para arreglar las porciones de su base de código que necesitan ser fijo. Es muy poco probable que necesite un asignador codificado a mano para todo su programa.


Depende mucho de tus patrones de asignación de memoria. Desde mi experiencia personal, generalmente hay una o dos clases en un proyecto que necesitan consideraciones especiales cuando se trata de la administración de la memoria, ya que se usan con frecuencia en la parte del código donde se gasta mucho tiempo. También podría haber clases que en algún contexto particular necesiten un tratamiento especial, pero en otros contextos pueden usarse sin preocuparse por ello.

A menudo termino administrando ese tipo de objetos en un std :: vector o algo similar y explícito en lugar de anular las rutinas de asignación para la clase. Para muchas situaciones el montón es realmente excesivo y los patrones de asignación son tan predecibles que no es necesario asignarlos en el montón, sino en una estructura mucho más simple que asigna páginas más grandes del montón que tiene menos sobrecarga de contabilidad que la asignación de cada instancia en el montón

Estas son algunas cosas generales para pensar:

En primer lugar, los objetos pequeños que se asignan y destruyen rápidamente deben colocarse en la pila. La asignación más rápida son las que nunca se hacen. La asignación de la pila también se realiza sin ningún bloqueo de un montón global que es bueno para el código de múltiples hilos. Asignar en el montón en c / c ++ puede ser relativamente costoso en comparación con los lenguajes de GC como Java, así que trate de evitarlo a menos que lo necesite.

Si realiza una gran cantidad de asignaciones, debe tener cuidado con el rendimiento de subprocesos. Una trampa clásica es que las clases de cuerdas tienden a hacer muchas asignaciones ocultas para el usuario. Si haces un montón de procesamiento de cadenas en varios hilos, pueden terminar peleando por un mutex en el código del montón. Para este propósito, tomar el control de la administración de la memoria puede acelerar mucho las cosas. Por lo general, cambiar a otra implementación de almacenamiento dinámico no es la solución aquí, ya que el montón seguirá siendo global y sus hilos de combate lucharán por ello. Creo que Google tiene un montón que debería ser más rápido en entornos multiproceso. No lo he probado yo mismo.


Solía ​​haber una excelente biblioteca de reemplazo de montón de terceros para VC ++, pero ya no recuerdo el nombre. Nuestra aplicación obtuvo un 30% de aceleración cuando comenzamos a usarla.

Editar: es SmartHeap - gracias, ChrisW


no, yo no lo haría.

Las posibilidades de que escriba un código mejor que el CRT con los que saben cuántos cientos de años invertidos en él son escasas.

Buscaría una biblioteca especializada en lugar de reinventar la rueda.


Aunque la mayoría de ustedes indica que no debe escribir su propio administrador de memoria, podría ser útil si:

  • tiene un requisito o situación específica en la que está seguro de que puede escribir una versión más rápida
  • desea escribir su propia lógica de sobrescritura de memoria (para ayudar en la depuración)
  • quieres hacer un seguimiento de los lugares donde se filtra la memoria

Si desea escribir su propio administrador de memoria, es importante dividirlo en las siguientes 4 partes:

  1. una parte que ''intercepta'' las llamadas a malloc / free (C) y new / delete (C ++). Esto es bastante fácil para new / delete (solo operadores globales new y delete), pero también para malloc / free esto es posible (''sobreescribir'' las funciones del CRT, redefinir llamadas a malloc / free, ...)
  2. una parte que representa el punto de entrada de su administrador de memoria, y que es llamada por la parte ''interceptor''
  3. una parte que implementa el administrador de memoria real. Posiblemente tendrá múltiples implementaciones de esto (dependiendo de la situación)
  4. una parte que ''decora'' la memoria asignada con información de la pila de llamadas, zonas de sobrescritura (también conocidas como zonas rojas), ...

Si estas 4 partes están claramente separadas, también es fácil reemplazar una parte por otra, o agregarle una parte nueva, por ejemplo:

  • agregar la implementación del administrador de memoria de la biblioteca Intel Tread Building Blocks (a la parte 3)
  • modifique la parte 1 para admitir una nueva versión del compilador, una nueva plataforma o un compilador totalmente nuevo

Al haber escrito un administrador de memoria, solo puedo indicar que puede ser realmente útil tener una forma fácil de ampliar su propio administrador de memoria. Por ejemplo, lo que regularmente tengo que hacer es encontrar pérdidas de memoria en aplicaciones de servidor de larga ejecución. Con mi propio administrador de memoria lo hago así:

  • inicia la aplicación y déjala ''calentar'' por un tiempo
  • pida a su propio administrador de memoria que descargue una descripción general de la memoria utilizada, incluidas las pilas de llamadas en el momento de la llamada
  • continúa ejecutando la aplicación
  • hacer un segundo botadero
  • ordenar los dos volcados alfabéticamente en la pila de llamadas
  • busca las diferencias

Aunque puede hacer cosas similares con componentes listos para usar, tienden a tener algunas desventajas:

  • A menudo ralentizan seriamente la aplicación
  • a menudo solo pueden informar fugas al final de la aplicación, no mientras la aplicación está ejecutándose

Pero también intente ser realista: si no tiene un problema con la fragmentación de la memoria, el rendimiento, las pérdidas de memoria o las sobreescrituras de memoria, no hay una razón real para escribir su propio administrador de memoria.


hay una solución utilizada por algún software de código abierto como doxygen, la idea es almacenar algunas instancias en el archivo cuando se supera una cantidad específica de memoria. Y después de obtener de archivo sus datos cuando los necesite.


Desde mi experiencia, la fragmentación es principalmente un problema cuando continuamente asigna y libera buffers grandes (como más de 16k) ya que esos son los que finalmente causarán una falta de memoria, si el montón no puede encontrar un lugar lo suficientemente grande para uno de ellos .

En ese caso, solo esos objetos deberían tener una administración de memoria especial, mantener el resto simple. Puede usar la reutilización de búfer si siempre tienen el mismo tamaño o una agrupación de memoria más compleja si varían en tamaño.

Las implementaciones de almacenamiento dinámico predeterminadas no deberían tener ningún problema para encontrar un lugar para búferes más pequeños entre asignaciones anteriores.