9

Tengo una clase pequeña (16 bytes en un sistema de 32 bits) que necesito asignar dinámicamente. En la mayoría de los casos, la vida útil de cualquier instancia dada es muy corta. Algunas instancias también pueden pasar a través de límites de subprocesos.Asignación eficiente de muchos objetos pequeños de vida corta

Después de haber hecho algunos perfiles, descubrí que mi programa parece estar dedicando más tiempo a asignar y desasignar las cosas que a gastar en usarlas, así que quiero reemplazar las nuevas predeterminadas y eliminarlas con algo que sea un poco más eficiente.

Para un objeto grande (conexiones db, que son costosas de construir en lugar de asignar), ya estoy usando un sistema de agrupación, sin embargo, eso implica una lista para almacenar los objetos "gratuitos" y también un mutex para seguridad de hilo. Entre el mutex y la lista en realidad funciona peor que con el nuevo/eliminar básico para los objetos pequeños.

me encontré con una serie de pequeños asignadores de objetos en Google, sin embargo, parecen estar utilizando un conjunto global/estática que no se utiliza de una manera segura hilo, que los hace inadecuados para mi uso :(

¿Qué otra tengo opciones para una gestión de memoria eficiente de objetos tan pequeños?

+1

Si objeta es muy pequeño, ¿por qué no simplemente pasar por valor? Además, ¿sus pequeños objetos son iguales, o son todos diferentes? Si es el primero, consulte boost.flyweight – KitsuneYMG

+0

Hay poca evidencia en su pregunta que sugiera que realmente puede hacerlo mejor. ¿Qué te hace pensar que haces? –

+0

Cuando escribe mutex, ¿quiere decir en general o mutex en particular? Si en particular, entonces CriticalSection será mejor siempre que no cruce los límites del proceso. –

Respuesta

0

Puede estar seguro de que está utilizando el low fragmentation heap. Está en modo predeterminado en Vista y más tarde, pero no creo que sea así con los sistemas operativos anteriores. Eso puede hacer una gran diferencia en la velocidad de asignación para objetos pequeños.

+0

Bueno, estoy probando en Vista, así que en ese caso ya está encendido. Aunque vale la pena saberlo porque estoy dando soporte a XP. –

+1

Es un tema interesante (más aún porque no tengo que resolverlo :). Tengo curiosidad por ver el solución final –

1

Quizás intente usi ng Google tcmalloc? Está optimizado para asignación/desasignación rápida en un programa enhebrado y tiene una sobrecarga baja para objetos pequeños.

1

algunos casos también pueden ser transmitidos a través de límites de rosca

Sólo "algo"? Entonces, quizás pueda pagar más por estos, si hace que los que no se pasan a otros hilos sean más baratos. Hay varias formas en que puedo pensar para llegar a un asignador por subproceso y evitar la necesidad de bloquearlo al asignar o liberar el hilo al que pertenece el asignador. No sé cuál podría ser posible en su programa:

  • Copie las cosas a través del límite del hilo, en lugar de pasarlas.

  • Disponer que si se pasan a otro hilo por cualquier motivo, se vuelven a pasar al hilo original para liberarlo. Esto no necesariamente tiene que suceder muy a menudo, puede poner en cola algunos en el hilo de recepción y pasarlos a todos en un mensaje más tarde. Esto supone, por supuesto, que el hilo que posee el asignador se mantendrá.

  • Tiene dos listas libres por asignador, una sincronizada (a la que se agregan los objetos cuando se liberan de otra cadena) y otra no sincronizada. Solo si la lista no sincronizada está vacía y está asignando (y por lo tanto en el hilo que posee el asignador), necesita bloquear la lista libre sincronizada y mover todos sus contenidos actuales a la lista no sincronizada. Si los objetos que se pasan a otros hilos son raros, esto básicamente elimina la contención en el mutex y reduce enormemente el número de veces que se toma.

  • Si todo lo anterior falla, tener un asignador por hilo aún podría permitirle deshacerse del mutex y usar una cola libre de bloqueos para la lista libre (liberación de múltiples escritores, asignación de lector único), lo que podría mejorar rendimiento un poco. La implementación de una cola libre de bloqueo es específica de la plataforma.

Dando un paso más atrás, que hace su aplicación con frecuencia alcanzó un estado en el que usted sabe que todas las células asignan después de cierto punto (quizás un poco en el pasado), ya no está en uso son? Si es así, y suponiendo que el destructor de sus pequeños objetos no hace nada terriblemente urgente, entonces no se moleste en liberar las celdas en absoluto; en el "cierto punto" cree un nuevo asignador y marque el antiguo como que ya no se usa para nuevas asignaciones. Cuando "golpee el estado", libere todo el asignador y su búfer subyacente. Si el "cierto punto" y el "estado" son simultáneos, todo es más fácil: simplemente reinicie su asignador.

+0

"después de cierto punto (quizás un poco en el pasado), ¿ya no están en uso?" desafortunadamente no, se usan durante toda la vida del programa. Siguiendo con el asignador único por hilo. ¿Qué pasa si creó un asignador de pool que tenía su lista gratuita en algún tipo de TLS. Entonces id solo necesita un proceso sincronizado ocasional para combatir la posibilidad de que los objetos migren de un hilo a otro haciendo que uno libere más de lo que asigna? –

+0

Sí, eso suena plausible. Cuanto más lenta sea la deriva de un hilo a otro, con menor frecuencia tendrá que sincronizar y menor será la sobrecarga. –

+0

También puede ver esto: http://goog-perftools.sourceforge.net/doc/tcmalloc.html –

Cuestiones relacionadas