2012-05-21 21 views
6

Tengo una sección de subprocesos múltiples donde los subprocesos necesitan asignar varios segmentos grandes de datos, digamos ~ 100MB cada uno, para usarlos como almacenamientos intermedios. Además, los almacenamientos intermedios pueden necesitar ser redimensionados en tiempo de ejecución varias veces.Sugerencia de asignación de memoria

La solución natural es usar realloc pero puede mover la memoria que no es necesaria. free/malloc par para cambiar el tamaño del búfer, me temo que puede conducir a la fragmentación y reservar memoria antes de que la mano cree otros problemas.

¿Qué puedo usar en su lugar, para asignar/reasignar memoria?

+0

"reservar memoria de antemano crea otros problemas" ¿Entonces un asignador de agrupamiento no es adecuado? ¿Y desea mantenerse estándar o está buscando enfoques para un esquema de asignación personalizado? – Corbin

+0

@ Corbin No creo que los pools sean buenos en mi caso: Linux tiene una política de primer toque en NUMA domanis. Me gustaría quedarme con la solución * portable * – Anycorn

+0

de cualquier forma de administrar los datos en los buffers de modo que pueda evitar el cambio de tamaño? o incluso poner un límite superior en el tamaño del búfer? ¿Cuánta memoria planeas tener en el hardware? –

Respuesta

5

Utilice free y malloc. Esto NO provocará problemas de fragmentación.

Las distribuidoras modernas son bastante resistentes a la fragmentación de la memoria. En estos días, se necesita un programa bastante patológico para causar problemas de fragmentación. La fragmentación fue un problema más grave cuando nuestros programas trataban directamente la memoria RAM física, pero con la memoria virtual, un gran "agujero" en el montón de un programa no necesita consumir ningún recurso.

Además, debido al tamaño de los almacenamientos intermedios, la mayoría de los asignadores solicitará una región dedicada del kernel para cada almacenamiento intermedio. En Linux/OS X/BSD, esto significa un mmap anónimo detrás de las escenas para cada buffer. Esto puede causar la fragmentación del espacio de direcciones, pero el espacio de direcciones virtuales es básicamente gratuito en un sistema de 64 bits, y unos pocos cientos de megas tampoco son un problema en 32 bits.

Así que use free y malloc.

Alternativa: Puede que le resulte más rápido hacer que cada memoria intermedia sea más grande de lo que necesita. La forma en que malloc funciona en un Unix moderno, cualquier página que no se escriba no consume memoria.

Si tiene malloc un buffer de 500 MB pero solo usa los primeros 100 MB, su programa no usa más memoria que si tiene malloc un buffer de 100 MB y use todo. Obtiene más fragmentación del espacio de direcciones de esta manera, pero eso no es un problema en los sistemas de 64 bits, y siempre puede ajustar el tamaño de asignación para que también funcione en sistemas de 32 bits.

En cuanto a la sugerencia de utilizar mmap, basta pensar en malloc/free como una interfaz más sencilla a mmap/munmap, que es lo que es para grandes asignaciones (1 MiB es un umbral común).

+0

¿Hay alguna referencia que describa bajo qué condición ocurre la fragmentación? – Anycorn

+0

Hay algunas cosas extrañas que puede hacer, como asignar un grupo de trozos de 16 bytes, liberar los impares, luego asignar un grupo de trozos de 24 bytes, liberar los impares y seguir haciendo cosas como ese. Básicamente es el peor de los casos para 'malloc', pero hay un límite en el porcentaje de memoria total desperdiciada. –

+1

@Anycorn: en realidad, ya que estamos hablando de grandes almacenamientos intermedios, en realidad se trata de * fragmentación de espacio de direcciones * y NO de fragmentación de memoria. Si tienes 64 bits, la fragmentación del espacio de direcciones no es algo que te importe. –

1

Implemente su solución con malloc/realloc/free y perfilela. Si la asignación de memoria es un problema, puede utilizar una mejor implementación de malloc como facebook jemalloc o google tcmalloc.

Consulte C++ memory allocation mechanism performance comparison (tcmalloc vs. jemalloc) para una comparación de los dos.

Ambos son bastante buenos en el manejo de las fragmentaciones internas/externas.

+1

Para buffers de 100 MB, no notará una diferencia entre jemalloc o tcmalloc porque ambos solicitan páginas directamente desde el kernel para asignaciones que superan un cierto umbral (1 MiB es común). El 'malloc' predeterminado en su sistema hará lo mismo. –

+0

@DietrichEpp el problema con el malloc predeterminado es la contención de bloqueo en el caso de aplicaciones de subprocesos múltiples. Aunque, sin duda, perfilé mi programa antes de usarlos. –

+1

Si está hablando de almacenamientos intermedios de 100 MB, el costo de un bloqueo incluso muy disputado será mínimo, porque de todos modos tiene que hacer un llamado al sistema. –

4

Simplemente use realloc. En un sistema moderno, incluso si el búfer se mueve a una nueva dirección, el cambio ocurrirá al manipular las tablas de páginas (en Linux, mremap; estoy seguro de que otros sistemas tienen un mecanismo similar) y no al copiar datos. (Tenga en cuenta que estoy asumiendo buffers grandes, para buffers pequeños, generalmente menos de unos cientos de kb, la copia real va a suceder.)

Si su objetivo son las máquinas de 64 bits, no hay necesidad de preocuparse por la fragmentación de la memoria. Nunca fragmentará la memoria lo suficiente como para quedarse sin espacio de direcciones virtuales. Si necesita manejar máquinas de 32 bits también, probablemente esté seguro siempre que no tenga demasiados hilos. Siempre que el consumo total de memoria sea inferior a 1 GB, sería muy difícil quedarse sin espacio de direcciones virtuales debido a la fragmentación, asumiendo su patrón de uso. Si le preocupa, simplemente preasigne el tamaño más grande que pueda necesitar.