¿Minimizar la cantidad de llamadas a malloc () mejora el rendimiento?


Considere dos aplicaciones: una (núm. 1) que invoca malloc() muchas veces, y el otro (núm. 2) que invoca malloc() pocas veces. Ambas aplicaciones asignan la misma cantidad de memoria (supongamos 100MB).
¿Para qué aplicación será más rápida la siguiente llamada a malloc (), #1 o #2?
En otras palabras: ¿Malloc() tiene un índice de ubicaciones asignadas en la memoria?

 27
Author: Jonathan Leffler, 2010-01-17

8 answers

Por supuesto, esto depende completamente de la implementación de malloc, pero en este caso, sin llamadas a free, la mayoría de las implementaciones de malloc probablemente le darán la misma velocidad algorítmica.

Como comentó otra respuesta, normalmente habrá una lista de bloques libres, pero si no has llamado libre, solo habrá uno, por lo que debería ser O(1) en ambos casos.

Esto asume que la memoria asignada para el montón es lo suficientemente grande en ambos casos. En el caso #1, habrá asignado más memoria total, ya que cada asignación implica sobrecarga de memoria para almacenar metadatos, como resultado puede que necesite llamar a sbrk (), o equivalente para hacer crecer el montón en el caso #1, lo que agregaría una sobrecarga adicional.

Probablemente serán diferentes debido a la caché y otros efectos de segundo orden, ya que las alineaciones de memoria para la nueva asignación no serán las mismas.

Si ha estado liberando algunos de los bloques de memoria, es probable que el #2 sea más rápido debido a una menor fragmentación, y así una lista más pequeña de bloques libres para buscar.

Si ha liberado todos los bloques de memoria, debería terminar siendo exactamente el mismo, ya que cualquier implementación libre sana habrá unido los bloques de nuevo en una sola arena de memoria.

 10
Author: benno,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-01-16 23:05:02

Usted hizo 2 preguntas:

  • ¿para qué aplicación será más rápida la próxima llamada a malloc (), #1 o #2?
  • En otras palabras: ¿Malloc() tiene un índice de ubicaciones asignadas en la memoria?

Usted ha dado a entender que son la misma pregunta, pero no lo son. La respuesta a esta última pregunta es SÍ.

En cuanto a cuál será más rápido, es imposible decirlo. Depende del algoritmo de asignación, el estado de la máquina, el fragmentación en el proceso actual, y así sucesivamente.

Sin embargo, su idea es sólida: debe pensar en cómo el uso de malloc afectará el rendimiento. Hubo una vez una aplicación que escribí que utiliza un montón de pequeñas manchas de memoria, cada uno asignado con malloc(). Funcionó correctamente pero fue lento. Reemplacé las muchas llamadas a malloc con solo una, y luego corté ese bloque grande dentro de mi aplicación. Fue mucho más rápido.

No recomiendo este enfoque; es solo una ilustración de la señale que el uso de malloc puede afectar materialmente el rendimiento.

Mi consejo es medirlo.

 18
Author: Cheeso,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-01-17 13:56:29

Malloc tiene que correr a través de una lista enlazada de bloques libres para encontrar uno para asignar. Esto lleva tiempo. Por lo tanto, #1 generalmente será más lento:

  • Cuanto más a menudo llame a malloc, más tiempo tomará, por lo que reducir el número de llamadas le dará una mejora de la velocidad (aunque si es significativo dependerá de sus circunstancias exactas).

  • Además, si malloc muchos bloques pequeños, a medida que libere esos bloques, fragmentará el montón mucho más que si solo asigna y libera unos cuantos bloques grandes. Por lo tanto, es probable que termine con muchos pequeños bloques libres en su montón en lugar de unos pocos bloques grandes, y por lo tanto, sus mallocs pueden tener que buscar más a través de las listas de espacios libres para encontrar un bloque adecuado para asignar. Lo que de nuevo los hará más lentos.

 6
Author: Jason Williams,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-01-16 22:41:51

Estos son, por supuesto, detalles de implementación, pero normalmente free() insertará la memoria en una lista de bloques libres. malloc() entonces buscará en esta lista un bloque libre que tenga el tamaño correcto, o más grande. Normalmente, solo si esto falla malloc() pide al núcleo más memoria.

También hay otras consideraciones, como cuándo fusionar múltiples bloques adyacentes en un solo bloque más grande.

Y, otra razón que malloc() es cara: Si malloc() se llama desde múltiples hilos, debe haber algún tipo de sincronización en estas estructuras globales. (es decir, cerraduras. Existen malloc() implementaciones con diferentes esquemas de optimización para hacerlo mejor para subprocesos múltiples, pero generalmente, mantenerlo seguro multi-subprocesos aumenta el costo, ya que varios subprocesos contenderán por esos bloqueos y bloquearán el progreso entre sí.

 3
Author: asveikau,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-01-16 22:48:31

La respuesta es que depende, la mayor parte de la lentitud potencial proviene más bien de malloc() y free() en combinación y generalmente #1 y #2 serán de velocidad similar.

Todas las implementaciones de malloc() tienen un mecanismo de indexación, pero la velocidad de agregar un nuevo bloque al índice generalmente no depende del número de bloques que ya están en el índice.

La mayor parte de la lentitud de malloc proviene de dos fuentes

  • buscando un bloque libre adecuado entre los previamente liberado(bloques)
  • problemas de multiprocesador con el bloqueo

Escribir mi propia herramienta de reemplazo malloc() casi compatible con los estándares malloc () y free() veces de 35% a 3-4%, y optimizó seriamente esos dos factores. Probablemente habría sido una velocidad similar usar algún otro malloc de alto rendimiento, pero tener el nuestro era más portátil para dispositivos esotéricos y, por supuesto, permite que free se inline en algunos lugares.

 2
Author: Erik Elmgren,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-01-16 22:46:18

Puedes siempre hacer un mejor trabajo usando malloc() para asignar una gran porción de memoria y subdividirla tú mismo. Malloc() fue optimizado para funcionar bien en el caso general y no hace suposiciones sobre si se usan hilos o cuál podría ser el tamaño de las asignaciones del programa.

Si es una buena idea implementar su propio sub-asignador es una pregunta secundaria. Rara vez lo es, la gestión explícita de la memoria ya es lo suficientemente difícil. Rara vez se necesita otra capa de código que puede arruinar y bloquear su programa sin ninguna buena manera de depurarlo. A menos que esté escribiendo un asignador de depuración.

 2
Author: Hans Passant,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-01-16 23:27:27

No se define la diferencia relativa entre "muchos" y "pocos", pero sospecho que la mayoría de los malloc funcionarían casi de manera idéntica en ambos escenarios. La pregunta implica que cada llamada a malloc tiene tanta sobrecarga como una llamada al sistema y actualizaciones de tabla de páginas. Cuando haces una llamada malloc, por ejemplo malloc(14), en un entorno sin muerte cerebral, malloc realmente asignará más memoria de la que pides, a menudo un múltiplo del tamaño de página de la MMU del sistema. Obtienes tus 14 bytes y malloc realiza un seguimiento de la área recién asignada para que las llamadas posteriores solo puedan devolver una parte de la memoria ya asignada, hasta que se necesite solicitar más memoria del sistema operativo.

En otras palabras, si llamo a malloc(14) 100 veces o malloc(1400) una vez, la sobrecarga será aproximadamente la misma. Tendré que manejar el trozo de memoria más grande asignado yo mismo.

 1
Author: Richard Pennington,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-01-16 23:05:32

Asignar un bloque de memoria es más rápido que asignar muchos bloques. Existe la sobrecarga de la llamada del sistema y también la búsqueda de bloques disponibles. En la programación, la reducción del número de operaciones suele acelerar el tiempo de ejecución.

Los asignadores de memoria pueden tener que buscar para encontrar un bloque de memoria que tenga el tamaño correcto. Esto se suma a la sobrecarga del tiempo de ejecución.

Sin embargo, puede haber mejores posibilidades de éxito al asignar pequeños bloques de memoria versus un bloque grande. Es su programa asignando un bloque pequeño y liberándolo o necesita asignar (y preservar) bloques pequeños. Cuando la memoria se fragmenta, hay menos trozos grandes disponibles, por lo que el asignador de memoria puede tener que unir todos los bloques para formar un bloque lo suficientemente grande para la asignación.

Si su programa está asignando y destruyendo muchos pequeños bloques de memoria, puede considerar asignar una matriz estática y usarla para su memoria.

 1
Author: Thomas Matthews,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-01-17 20:27:25