Asignación de memoria del sistema utilizando el subsistema malloc

La memoria se asigna a las aplicaciones que utilizan el subsistema malloc .

El subsistema malloc es una API de gestión de memoria que consta de las subrutinas siguientes:

  • malloc
  • calloc
  • reasignación
  • free
  • mallopt
  • mallinfo
  • alóca
  • valloc
  • posix_memalign

El subsistema malloc gestiona un objeto de memoria lógica denominado almacenamiento dinámico. El almacenamiento dinámico es una región de memoria que reside en el espacio de direcciones de la aplicación entre el último byte de datos asignado por el compilador y el final de la región de datos. El almacenamiento dinámico es el objeto de memoria desde el que se asigna memoria y a la que la API del subsistema malloc devuelve memoria.

El subsistema malloc realiza las siguientes operaciones de memoria fundamentales:
  • Asignación:

    Realizado por las subrutinas malloc, calloc valloc, allocay posix_memalign .

  • Desasignación:

    Realizado por la subrutina free .

  • Reasignación:

    Realizado por la subrutina realloc .

Las subrutinas mallopt y mallinfo están soportadas para la compatibilidad con System V. La subrutina mallinfo se puede utilizar durante el desarrollo del programa para obtener información sobre el almacenamiento dinámico gestionado por la subrutina malloc . La subrutina mallopt se puede utilizar para descartar la memoria libre de tamaño de página alineada con páginas y para habilitar e inhabilitar el asignador predeterminado. De forma similar a la subrutina malloc , se proporciona la subrutina valloc para la compatibilidad con Berkeley Compatibility Library.

Para obtener información adicional, consulte las secciones siguientes:

Trabajar con el almacenamiento dinámico de proceso

_edata es un símbolo cuya dirección es el primer byte después del último byte de datos de programa inicializados. El símbolo _edata hace referencia al inicio del almacenamiento dinámico de proceso, que se amplía mediante el subsistema malloc cuando se asigna el primer bloque de datos. El subsistema malloc aumenta el almacenamiento dinámico de proceso aumentando el valor brk de proceso, que indica el final del almacenamiento dinámico de proceso. Esto se realiza llamando a la subrutina sbrk . El subsistema malloc expande el almacenamiento dinámico de proceso según las necesidades de la aplicación.

El almacenamiento dinámico de proceso se divide en bloques de memoria asignados y liberados . La agrupación libre consta de la memoria disponible para la asignación posterior. Una asignación se completa eliminando primero un bloque de memoria de la agrupación libre y luego devolviendo a la función de llamada un puntero a este bloque. Se completa una reasignación asignando un bloque de memoria del nuevo tamaño, moviendo los datos del bloque original al nuevo bloque y liberando el bloque original. Los bloques de memoria asignados constan de las partes del almacenamiento dinámico de proceso que utiliza la aplicación. Puesto que los bloques de memoria no se eliminan físicamente del almacenamiento dinámico (cambian el estado de libre a asignado), el tamaño del almacenamiento dinámico de proceso no disminuye cuando la aplicación libera memoria.

Espacio de direcciones de proceso en aplicaciones de 32 bits

Un programa de aplicación de 32 bits que se ejecuta en el sistema tiene un espacio de direcciones dividido en los segmentos siguientes:

Segmento Descripción
0x00000000por:0x0fffffff Contiene el kernel.
0x10000000por:0x1fffffff Contiene el texto del programa de aplicación.
0x20000000por:0x2fffffff Contiene los datos del programa de aplicación, el almacenamiento dinámico de proceso y la pila de aplicación.
0x30000000por:0xcfffffff Disponible para que lo utilicen la memoria compartida o los servicios mmap .
0xd0000000por:0xdfffffff Contiene texto de biblioteca compartida.
0xe0000000por:0xefffffff Disponible para que lo utilicen la memoria compartida o los servicios mmap .
0xf0000000por:0xffffffff Contiene los datos de la biblioteca compartida de la aplicación.

Espacio de direcciones de proceso en aplicaciones de 64 bits

Un programa de aplicación de 64 bits que se ejecuta en el sistema tiene un espacio de direcciones dividido en los segmentos siguientes:

Segmento Descripción
0x0000 0000 0000 0000por:0x0000 0000 0fff ffff Contiene el kernel.
0x0000 0000 f000 0000por:0x0000 0000 ffff ffff Reservado.
0x0000 0001 0000 0000por:0x07ff ffff ffff ffff Contiene el texto del programa de aplicación, los datos del programa de aplicación, el almacenamiento dinámico de proceso y la memoria compartida o los servicios mmap .
0x0800 0000 0000 0000por:0x08ff ffff ffff ffff Objetos cargados de forma privada.
0x0900 0000 0000 0000por:0x09ff ffff ffff ffff Texto y datos de biblioteca compartida.
0x0f00 0000 0000 0000por:0x0fff ffff ffff ffff Pila de aplicación.
Nota: AIX® utiliza una técnica de asignación de ranuras de paginación retardada para el almacenamiento asignado a las aplicaciones. Cuando se asigna almacenamiento a una aplicación con una subrutina, como por ejemplo malloc, no se asigna ningún espacio de paginación a ese almacenamiento hasta que se hace referencia al almacenamiento. Esta técnica es útil para aplicaciones que asignan grandes segmentos de memoria dispersa. Sin embargo, esta técnica puede afectar a la portabilidad de las aplicaciones que asignan cantidades muy grandes de memoria. Si la aplicación espera que las llamadas a malloc fallen cuando no haya suficiente almacenamiento de respaldo para dar soporte a la solicitud de memoria, es posible que la aplicación asigne demasiada memoria. Cuando se hace referencia a esta memoria más adelante, la máquina se queda rápidamente sin espacio de paginación y el sistema operativo interrumpe los procesos para que el sistema no se agote completamente de memoria virtual. La aplicación que asigna memoria debe asegurarse de que existe almacenamiento de reserva para el almacenamiento que se está asignando. Establecer la variable de entorno PSALLOC en PSALLOC=early cambia la técnica de asignación de espacio de paginación a un algoritmo de asignación temprana. En la asignación temprana, el espacio de paginación se asigna una vez que se solicita la memoria. Para obtener más información, consulte Espacio de paginación y memoria virtual en Sistema operativo y gestión de dispositivos.

Descripción de la política de asignación del sistema

La política de asignación hace referencia al conjunto de estructuras de datos y algoritmos empleados para representar el almacenamiento dinámico y para implementar la asignación, la desasignación y la reasignación. El subsistema malloc soporta varias políticas de asignación diferentes, incluyendo la política de asignación predeterminada, la política de asignación de Watson, la política de asignación malloc 3.1 y la política de asignación definida por el usuario. La API para acceder al subsistema malloc es idéntica para todas las políticas de asignación; sólo la implementación subyacente es diferente.

Puede utilizar las siguientes variables de entorno para especificar la política de asignación y cualquier opción normal o de depuración para dicha política:
  • MALLOCTYPE especifica la política de asignación.
  • MALLOCOPTIONS especifica opciones normales para la política de asignación elegida.
  • MALLOCDEBUG especifica opciones de depuración para la política de asignación elegida.
  • MALLOCALIGN especifica la alineación malloc predeterminada externa a un programa.

La política de asignación predeterminada es generalmente más eficiente y es la opción preferida para la mayoría de las aplicaciones. Las otras políticas de asignación tienen algunas características de comportamiento exclusivas que pueden ser beneficiosas en circunstancias específicas, tal como se describe en Comparación de las distintas políticas de asignación.

Algunas opciones de las distintas políticas de asignación son compatibles entre sí y pueden utilizarse conjuntamente. Cuando utilice opciones en tándem, utilice una coma (,) para separar las opciones especificadas por las variables de entorno MALLOCOPTIONS y MALLOCDEBUG .

La variable de entorno MALLOCALIGN se puede establecer en la alineación predeterminada deseada para cada asignación malloc () . Como por ejemplo,
MALLOCALIGN=16;  export MALLOCALIGN
La variable de entorno MALLOCALIGN se puede establecer en cualquier potencia de 2 valores mayor o igual que el tamaño de un puntero en la modalidad de ejecución correspondiente (4 bytes para la modalidad de 32 bits, 8 bytes para la modalidad de 64 bits). Para programas habilitados para vectores de 32 bits, esta variable de entorno se puede establecer en 16, por lo que todos los malloc ()se alinearán adecuadamente para los tipos de datos de vector si es necesario. Tenga en cuenta que los programas vectoriales de 64 bits ya recibirán asignaciones alineadas de 16 bytes.

Además, internamente en un programa, el programa puede utilizar la rutina mallopt (M_MALIGN, 16) para cambiar el valor predeterminado malloc () para proporcionar asignaciones alineadas de 16 bytes. La rutina mallopt (M_MALIGN) permite que un programa controle la alineación malloc predeterminada dinámicamente en tiempo de ejecución.

Descripción de la política de asignación predeterminada

La política de asignación predeterminada mantiene el espacio libre en el almacenamiento dinámico como nodos en un árbol de búsqueda binario cartesiano en el que los nodos se ordenan de izquierda a derecha por dirección (aumentando la dirección a la derecha) y de arriba a abajo por longitud (de modo que ningún hijo es mayor que su padre). Esta estructura de datos no impone ninguna limitación en el número de tamaños de bloque soportados por el árbol, lo que permite una amplia gama de tamaños de bloque potenciales. Las técnicas de reorganización de árbol optimizan los tiempos de acceso para la ubicación, inserción y supresión de nodos y también protegen contra la fragmentación.

La política de asignación predeterminada proporciona soporte para las siguientes prestaciones opcionales:

Asignación

Se necesita una pequeña cantidad de sobrecarga para dar servicio a una solicitud de asignación. Esto se debe a la necesidad de un prefijo de metadatos y a la necesidad de una alineación adecuada de cada bloque de memoria. El tamaño del prefijo de metadatos para todas las asignaciones es de 8 y 16 bytes para programas de 32 y 64 bits respectivamente. Cada bloque debe estar alineado en un límite de 16 o 32 bytes, por lo que la cantidad total de memoria necesaria para una asignación de tamaño n es:

size = roundup(n + prefix_size, alignment requirement)

Por ejemplo, una asignación de tamaño 37 en un proceso de 32 bits requeriría roundup(37 + 8, 16), que es igual a 48 bytes.

El nodo del árbol con la dirección más baja que es mayor o igual que el tamaño necesario se elimina del árbol. Si el bloque encontrado es mayor que el tamaño necesario, el bloque se divide en dos bloques: uno del tamaño necesario y el segundo un resto. El segundo bloque, denominado runt, se devuelve al árbol libre para su futura asignación. El primer bloque se devuelve al interlocutor.

Si no se encuentra un bloque de tamaño suficiente en el árbol libre, el almacenamiento dinámico se expande, se añade al árbol libre un bloque del tamaño de la extensión adquirida y la asignación continúa tal como se ha descrito anteriormente.

Desasignación

Los bloques de memoria desasignados con la subrutina free se devuelven al árbol, en la raíz. Cada nodo a lo largo de la vía de acceso al punto de inserción para el nuevo nodo se examina para ver si se une al nodo que se está insertando. Si lo hace, los dos nodos se fusionan y el nodo recién fusionado se reubica en el árbol. Si no se encuentra ningún bloque contiguo, el nodo simplemente se inserta en el lugar adecuado del árbol. La fusión de bloques adyacentes puede reducir significativamente la fragmentación del almacenamiento dinámico.

Reasignación

Si el tamaño del bloque reasignado será mayor que el bloque original, el bloque original se devuelve al árbol libre con la subrutina free para que pueda producirse cualquier posible coalescencia. A continuación, se asigna un nuevo bloque del tamaño solicitado, los datos se mueven del bloque original al nuevo bloque y el nuevo bloque se devuelve al interlocutor.

Si el tamaño del bloque reasignado es menor que el bloque original, el bloque se divide y el más pequeño se devuelve al árbol libre.

Limitaciones

La política de asignación predeterminada da soporte a las opciones siguientes:

Visión general de la política de asignación de Watson

La política de asignación de Watson mantiene el espacio libre en el almacenamiento dinámico como nodos en dos árboles rojo-negro separados: uno ordenado por dirección y el otro por tamaño. Los árboles rojo-negros proporcionan operaciones de árbol más sencillas y eficientes que los árboles cartesianos del asignador predeterminado, por lo que la política de asignación de Watson suele ser más rápida que la predeterminada.

Asignación

La política de asignación de Watson tiene los mismos requisitos de sobrecarga que la política de asignación predeterminada.

Se busca en el árbol de tamaño el bloque más pequeño posible que sea mayor o igual que el tamaño necesario. A continuación, este bloque se elimina del árbol de tamaño. Si el bloque encontrado es mayor que el tamaño necesario, el bloque se divide en dos bloques: un bloque del tamaño restante y el segundo del tamaño requerido. El primer bloque, denominado runt, se devuelve al árbol de tamaño para su futura asignación. El segundo bloque se devuelve al interlocutor. Si el bloque encontrado en el árbol de tamaño era exactamente el tamaño necesario, el bloque se elimina del tamaño y del árbol de direcciones y, a continuación, se devuelve al llamante.

Si no se encuentra un bloque de tamaño suficiente en el árbol libre, el almacenamiento dinámico de proceso se expande, se añade un bloque del tamaño de esta expansión a los árboles de tamaño y dirección, y la asignación continúa como se ha descrito anteriormente.

Desasignación

Los bloques de memoria desasignados con la subrutina free se devuelven al árbol de direcciones en la raíz. Cada nodo a lo largo de la vía de acceso al punto de inserción para el nuevo nodo se examina para ver si se une al nodo que se está insertando. Si lo hace, los dos nodos se fusionan y el nodo recién fusionado se reubica en el árbol de tamaño. Si no se encuentra ningún bloque contiguo, el nodo simplemente se inserta en el lugar adecuado en el árbol de direcciones y tamaño.

Después de la inserción, se debe comprobar el equilibrio correcto en ambos árboles rojo-negro.

Reasignación

Si el tamaño del bloque reasignado será mayor que el bloque original, el bloque original se devuelve a los árboles libres con la subrutina free para que se pueda producir cualquier posible coalescencia. A continuación, se asigna un nuevo bloque del tamaño solicitado, los datos se mueven del bloque original al nuevo bloque y el nuevo bloque se devuelve al interlocutor.

Si el tamaño del bloque reasignado es menor que el bloque original, el bloque se divide y el resto se devuelve al árbol libre.

Limitaciones

La política de asignación de Watson da soporte a las opciones siguientes:

Política de asignación de malloc 3.1

La política de asignación de malloc 3.1 se puede seleccionar estableciendo MALLOCTYPE=3.1 antes del inicio del proceso. A partir de entonces, todos los programas de 32 bits ejecutados por el shell utilizarán la política de asignación malloc 3.1 (los programas de 64 bits seguirán utilizando la política de asignación predeterminada).

La política de asignación malloc 3.1 mantiene el almacenamiento dinámico como un conjunto de 28 grupos hash, cada uno de los cuales apunta a una lista enlazada. Cada lista enlazada contiene bloques de un tamaño determinado. El índice en los grupos hash indica el tamaño de los bloques de la lista enlazada. El tamaño del bloque se calcula utilizando la fórmula siguiente:
size = 2 i + 4
donde i identifica el grupo. Esto significa que los bloques de la lista anclados por el grupo cero tienen una longitud de 20 + 4 = 16 bytes. Por lo tanto, dado que un prefijo tiene un tamaño de 8 bytes, estos bloques pueden satisfacer solicitudes de bloques de entre 0 y 8 bytes de longitud. La tabla siguiente ilustra cómo se distribuyen los tamaños solicitados entre los grupos.
Nota: Este algoritmo puede utilizar hasta el doble de la cantidad de memoria realmente solicitada por la aplicación. Se necesita una página adicional para grupos de más de 4096 bytes porque los objetos de un tamaño de página o más grande están alineados con la página. Puesto que el prefijo precede inmediatamente al bloque, se necesita una página entera únicamente para el prefijo.
Grupo Tamaño de bloque Tamaños correlacionados Páginas utilizadas
0 16 0 ... 8  
1 32 9 ... 24  
2 64 25 ... 56  
3 128 57 ... 120  
4 256 121 ... 248  
5 512 249 ... 504  
6 1K 505 ... 1K-8  
7 2K 1K-7 ... 2K-8  
8 4K 2K-7 ... 4K-8 2
9 8K 4K-7 ... 8K-8 3
10 16K 8K-7 ... 16K-8 5
5 32K 16K-7 ... 32K-8 9
6 64K 32K-7 ... 64K-8 17
13 128K 64K-7 ... 128K-8 33
14 256K 128K-7 ... 256K-8 65
15 512K 256K-7 ... 512K-8 129
16 1M 256K-7 ... 1M-8 257
17 2M 1M-7 ... 2M-8 513
18 4M 2M-7 ... 4M-8 1K + 1
19 8M 4M-7 ... 8M-8 2K + 1
20 16M 8M-7 ... 16M-8 4K + 1
21 32M 16M-7 ... 32M-8 8K + 1
22 64M 32M-7 ... 64M-8 16K + 1
23 128M 64M-7 ... 128M-8 32K + 1
24 256M 128M-7 ... 256M-8 64K + 1
25 512M 256M-7 ... 512M-8 128K + 1
26 1024M 512M-7 ... 1024M-8 256K + 1
27 2048M 1024M-7 ... 2048M-8 512K + 1

Asignación

Un bloque se asigna desde la agrupación libre convirtiendo primero los bytes solicitados en un índice en la matriz de grupos, utilizando la ecuación siguiente:

needed = requested + 8

If needed <= 16,
then
bucket = 0

If needed > 16,
then
bucket = (log(needed)/log(2) rounded down to the nearest integer) - 3

El tamaño de cada bloque de la lista anclada por el grupo esblock size = 2 bucket + 4. Si la lista del grupo es nula, la memoria se asigna utilizando la subrutina Sbrk para añadir bloques a la lista. Si el tamaño de bloque es menor que una página, se asigna una página utilizando la subrutina sbrk y el número de bloques a los que se ha llegado dividiendo el tamaño de bloque en el tamaño de página se añade a la lista. Si el tamaño de bloque es igual o mayor que una página, la memoria necesaria se asigna utilizando la subrutina sbrk y se añade un único bloque a la lista de libres para el grupo. Si la lista libre no está vacía, el bloque situado al principio de la lista se devuelve al llamante. El siguiente bloque de la lista se convierte entonces en la nueva cabeza.

Desasignación

Cuando se devuelve un bloque de memoria a la agrupación libre, el índice de grupo se calcula como con asignación. A continuación, el bloque que se va a liberar se añade a la cabecera de la lista de libres para el grupo.

Reasignación

Cuando se reasigna un bloque de memoria, el tamaño necesario se compara con el tamaño existente del bloque. Debido a la varianza amplia en tamaños manejados por un solo grupo, el nuevo tamaño de bloque a menudo se correlaciona con el mismo grupo que el tamaño de bloque original. En estos casos, la longitud del prefijo se actualiza para reflejar el nuevo tamaño y se devuelve el mismo bloque. Si el tamaño necesario es mayor que el bloque existente, el bloque se libera, se asigna un bloque nuevo del nuevo grupo y los datos se mueven del bloque antiguo al bloque nuevo.

Limitaciones

El establecimiento de MALLOCTYPE=3.1 solo habilitará la política malloc 3.1 para programas de 32 bits. Para que los programas de 64 bits utilicen la política malloc 3.1 , la variable de entorno MALLOCTYPE debe establecerse explícitamente en MALLOCTYPE=3.1_64BIT. Esta política de asignación es menos eficaz que la predeterminada y no se recomienda su uso en la mayoría de los casos.

La política de asignación malloc 3.1 da soporte a las opciones siguientes:

Descripción de la política de asignación de agrupaciones

La agrupación Malloc es un front-end de alto rendimiento para las funciones de libc malloc, calloc, free, posix_memalign y realloc para gestionar objetos de almacenamiento menores de 513 bytes. Las ventajas de rendimiento se derivan de longitudes de vía de acceso mucho más cortas y de una mejor utilización de la memoria caché de datos. Para aplicaciones multihebra, existe la ventaja adicional de que las anclas de agrupación local de hebras se utilizan para evitar operaciones atómicas. Este front-end se puede utilizar junto con cualquiera de los esquemas de gestión de almacenamiento que se proporcionan actualmente en libc (yorktowny watson).

Para utilizar la agrupación malloc , ejecute el mandato siguiente:
export MALLOCOPTIONS=pool<:max_size>

Cuando se especifica esta opción, se crea una colección de agrupaciones durante la inicialización de malloc donde cada agrupación es una lista enlazada de objetos de tamaño fijo. La agrupación más pequeña puede contener objetos de tamaño de puntero (por ejemplo, 8 bytes para aplicaciones de 32 bits o 16 bytes para aplicaciones de 64 bits). Cada agrupación sucesiva puede acomodar objetos cuyo tamaño sea mayor que la agrupación anterior. Esto significa que hay 128 agrupaciones para aplicaciones de 32 bits y 64 agrupaciones para aplicaciones de 64 bits. La colección de agrupaciones se representa como una matriz de punteros que "anclan" las listas enlazadas.

La agrupación Malloc utiliza su propia memoria, el almacenamiento dinámico de la agrupación, que no se comparte con mallocestándar. Cuando se especifica, la opción max_size se redondea al siguiente valor superior de 2 MB y se utiliza para controlar el tamaño del almacenamiento dinámico de la agrupación. La opción max_size se puede especificar como un número decimal o un número hexadecimal precedido por 0x o 0X (por ejemplo, export MALLOCOPTIONS=pool:0x1700000 establecerá max_size en 24 MB después del redondeo.

Para aplicaciones de 32 bits, el tamaño del almacenamiento dinámico de agrupación se inicia en 2 MB. Si se necesita más almacenamiento y el almacenamiento dinámico total de la agrupación es menor que tamaño_máx, se adquieren 2 MB adicionales. Cada área de 2 MBb estará en un límite de 2 MB, pero no es necesario que sea contigua a ninguna de las otras áreas de 2 MB. Para aplicaciones de 64 bits, se asigna un único almacenamiento dinámico de agrupación contigua de max_size durante la inicialización de malloc y nunca se amplía. Si no se especifica max_size , el valor predeterminado es 512 MB para aplicaciones de 32 bits y 32 MB para aplicaciones de 64 bits. Para las modalidades de 32 y 64 bits, tamaño_máximo se establecerá en 512 MB si se especifica un tamaño mayor. Para la modalidad de 32 bits, max_size se establece en 512MB, y para la modalidad de 64 bits, max_size se establece en 3.7 GB si se especifica un tamaño mayor.

Utilización de almacenamiento

Todas las anclas de agrupación se establecen inicialmente en NULL o están vacías. Cuando la agrupación malloc da servicio a una solicitud y la agrupación correspondiente está vacía, se llama a una rutina que asigna almacenamiento del almacenamiento dinámico de la agrupación en fragmentos de 1024 bytes contiguos en límites de 1024 bytes. Se "crean" varios objetos del tamaño solicitado. La dirección del primero se devuelve para satisfacer la solicitud, mientras que los objetos restantes se enlazan entre sí y se colocan en el ancla de la agrupación. Para cada fragmento de 1024 bytes, hay una entrada de 2 bytes en una tabla auxiliar que utiliza free para determinar el tamaño de un objeto devuelto.

Cuando una agrupación malloc libera un objeto, simplemente se "envía" al ancla de agrupación adecuada. No se realiza ningún intento de fusionar bloques para crear objetos de mayor tamaño.

Debido a este comportamiento, la agrupación malloc puede utilizar más almacenamiento que otras formas de malloc.

Alineación

La alineación predeterminada para las subrutinas malloc (), calloc ()y realloc () debe especificarse estableciendo la variable de entorno MALLOCALIGN de forma adecuada. La subrutina posix_memalign () continúa funcionando incluso si la variable de entorno MALLOCALIGN no está establecida. Si MALLOCALIGN es mayor que 512, no se utiliza la agrupación malloc .

Eficiencia de memoria caché

Los objetos de memoria asignados con agrupación malloc no tienen prefijos ni sufijos. Por lo tanto, las líneas de memoria caché de datos están más densamente empaquetadas con los datos utilizables de la aplicación. Como todos los objetos de memoria que tienen una potencia de 2 en tamaño están alineados en un límite igual a ese tamaño, cada objeto está contenido dentro del número mínimo de líneas de memoria caché. Las subrutinas malloc y free no exploran árboles ni listas enlazadas y, por lo tanto, no "contaminan" la memoria caché.

Soporte multihebra

Las agrupaciones Malloc pueden mejorar el rendimiento de forma significativa en un escenario multihebra porque reduce la contención de bloqueo y la necesidad de operaciones atómicas.

Soporte de equilibrio de carga

En algunos escenarios multihebra, la agrupación libre de una hebra puede crecer muy grande debido a la liberación repetitiva de memoria asignada dinámicamente. Sin embargo, es posible que otras hebras no puedan utilizar esta memoria.

El soporte de equilibrio de carga hace que una hebra libere la mitad de la memoria de cada agrupación a una agrupación global después de que la agrupación alcance un valor de umbral para que otras hebras puedan utilizarla. Puede ajustar los valores de umbral en los que se reajustará la agrupación de hebras.

Para activar el soporte de equilibrio de carga, se deben exportar las opciones siguientes:

export MALLOCOPTIONS=pool:0x80000000,pool_balanced
export MALLOCFREEPOOL=min_size<-max_size>:threshold_value<,min_size<-max_size>:
threshold_value, ... >,default:threshold
El ejemplo siguiente establece el valor de umbral para las agrupaciones que proporcionan una memoria de 0 -16 bytes y 256 fragmentos, y el valor de umbral de la agrupación que sirve fragmentos de 32 bytes a fragmentos de 512 bytes. Para el resto de las agrupaciones, los fragmentos de 128 bytes es el valor de umbral.
export MALLOCFREEPOOL=0-16:256,32:512,default:128

Soporte de depuración

No hay ninguna versión de depuración de este front-end de alto rendimiento. Si se establece la variable de entorno MALLOCDEBUG , la opción de agrupación se ignora. Se espera que las aplicaciones se depurarán utilizando malloc "normal" antes de activar la agrupación.

Descripción de la política de asignación definida por el usuario

El subsistema malloc proporciona un mecanismo a través del cual los usuarios pueden desarrollar sus propios algoritmos para gestionar el almacenamiento dinámico del sistema y asignar memoria.

Descripción de la opción no_overwrite

Una opción adicional disponible para todas las políticas de asignación es no_overwrite. Para reducir la sobrecarga del código glink dentro del subsistema malloc, el descriptor de función para las API del subsistema malloc se sobrescribe con el descriptor de función para la implementación subyacente real. Puesto que algunos programas, como los depuradores de terceros, pueden no funcionar cuando los punteros de función se modifican de esta forma, se puede utilizar la opción no_overwrite para inhabilitar esta optimización.

Para inhabilitar esta optimización, establezca MALLOCOPTIONS=no_overwrite antes del inicio del proceso.

Comparación de las distintas políticas de asignación

Las diversas políticas de asignación de malloc elaboradas anteriormente proporcionan flexibilidad a los desarrolladores de aplicaciones cuando se utilizan por separado o se combinan de formas soportadas. Es responsabilidad del desarrollador reconocer las necesidades exclusivas de una aplicación y ajustar los diversos parámetros de política de asignación de forma beneficiosa.

Comparación de las políticas de asignación predeterminadas y malloc 3.1

Puesto que la política de asignación malloc 3.1 redondea el tamaño de cada solicitud de asignación a la siguiente potencia de 2, puede producir una fragmentación de memoria virtual y real considerable y una localidad pobre de referencia. La política de asignación predeterminada es generalmente una mejor opción porque asigna exactamente la cantidad de espacio solicitada y es más eficiente en la reclamación de bloques de memoria utilizados anteriormente.

Desafortunadamente, algunos programas de aplicación pueden depender inadvertidamente de los efectos secundarios de la política de asignación malloc 3.1 para un rendimiento aceptable o incluso para un funcionamiento correcto. Por ejemplo, un programa que sobrepasa el final de una matriz puede funcionar correctamente cuando se utiliza el asignador malloc 3.1 sólo debido al espacio adicional proporcionado por el proceso de redondeo. Es probable que el mismo programa experimente un comportamiento errático o incluso falle cuando se utiliza con el asignador por omisión porque el asignador por omisión sólo asigna el número de bytes solicitado.

Como otro ejemplo, debido a la ineficiente reclamación de espacio del algoritmo de asignación malloc 3.1 , el programa de aplicación casi siempre recibe espacio que se ha establecido en ceros (cuando un proceso toca una página determinada en su segmento de trabajo por primera vez, esa página se establece en ceros). Las aplicaciones pueden depender de este efecto secundario para una ejecución correcta. De hecho, la reducción a cero del espacio asignado no es una función especificada de la subrutina malloc y daría como resultado una penalización de rendimiento innecesaria para los programas que se inicializan sólo según sea necesario y posiblemente no a ceros. Puesto que el asignador predeterminado es más agresivo sobre la reutilización de espacio, los programas que dependen de la recepción de almacenamiento con ceros de malloc probablemente fallarán cuando se utilice el asignador predeterminado.

De forma similar, si un programa reasigna continuamente una estructura a un tamaño ligeramente mayor, es posible que el asignador malloc 3.1 no tenga que mover la estructura con mucha frecuencia. En muchos casos, la subrutina realloc puede utilizar el espacio adicional proporcionado por el redondeo implícito en el algoritmo de asignación malloc 3.1 . El asignador predeterminado normalmente tendrá que mover la estructura a un área ligeramente más grande debido a la probabilidad de que la subrutina malloc llame a otra cosa justo por encima de ella. Esto puede presentar el aspecto de una degradación en el rendimiento de la subrutina realloc cuando se utiliza el asignador predeterminado en lugar del asignador malloc 3.1 . En realidad, es la afloración de un coste que está implícito en la estructura del programa de aplicación.

Depuración de la gestión incorrecta de la aplicación del almacenamiento dinámico del sistema

El subsistema malloc ofrece una colección de herramientas de depuración pensadas para ayudar al desarrollador de aplicaciones a depurar y corregir errores en la gestión de almacenamiento dinámico de un programa. Estas herramientas de depuración se controlan mediante la variable de entorno MALLOCDEBUG .

Sinopsis de la variable de entorno malloc y opciones

La tabla siguiente muestra la compatibilidad entre las variables de entorno MALLOCTYPE y MALLOCOPTIONS .
Tabla 1. Compatibilidad entre MALLOCTYPE y MALLOCOPTIONS Variables de entorno
  multiheap (y subopciones) grupos (y subopciones) Memoria caché de hebras no reclamar no_sobrescritura
Asignador predeterminado
3.1 No No
Watson No No No No No
Watson2 No No No No No
usuario: No No No No
Tabla 2. Compatibilidad entre MALLOCDEBUG y MALLOCTYPE Variables de entorno
  York Town < Asignador predeterminado > 3.1 Watson Watson2 usuario:
catch_overflow (y subopciones) No No
asignaciones de informes No No
comprobación_postlibre No No
validate_ptrs No No
rastreo No No
anotaciones No No
verbose No No No No No
Todas las opciones MALLOCDEBUG son compatibles y están soportadas con MALLOCOPTIONS.

Descripción de la política de asignación de Watson2

El subsistema malloc Watson2 se adapta al comportamiento de la aplicación cuando cambia de una sola hebra a varias hebras y de varias hebras a una sola hebra. Utiliza un mecanismo específico de hebra que utiliza un número variable de estructuras de almacenamiento dinámico, que dependen del comportamiento del programa. Por lo tanto, no se necesitan opciones de configuración. El subsistema malloc Watson2 tiene O (logN) amortizado el coste por operación para muchas cargas de trabajo porque se puede ejecutar un gran número de operaciones en un momento constante sin sincronización.

Asignación

La asignación se maneja mediante una combinación de mecanismos. Estos mecanismos dependen de parámetros como, por ejemplo, el número de hebras activas, el tamaño de la solicitud y el historial de desasignación del proceso. El conjunto de mecanismos alcanza desde un almacenamiento en memoria caché específico de hebra y utiliza un número variable de almacenamientos dinámicos, que tiene afinidad de hebras con un árbol doble rojo-negro y fusión basada en página.

Desasignación

La desasignación depende de los mismos parámetros que el comportamiento de asignación. Normalmente, un bloque de devolución se captura en la memoria caché específica de hebra. En función de la afinidad de almacenamiento dinámico y la utilización de capacidad, la memoria puede devolverse a una de las varias estructuras de almacenamiento dinámico. A veces, el contenido de la estructura de almacenamiento dinámico múltiple se consolida en una estructura de almacenamiento dinámico común para mejorar la fusión y reducir la fragmentación del almacenamiento dinámico. Para mejorar la robustez frente a errores de aplicación, el asignador identifica la desasignación de punteros no válidos o bloques dañados, hasta cierto punto y filtra estas operaciones.

Reasignación

Los bloques grandes de memoria que son adecuados se reutilizan. Si el bloque actual no puede satisfacer la solicitud, se sustituye por una desasignación y asignación regulares.

Limitaciones

El subsistema malloc Watson2 se adapta a la aplicación y no requiere más opciones, pero el subsistema malloc Watson2 soporta las siguientes características de depuración controladas por la variable MALLOCDEBUG : validate_ptrs, report_allocations, y trace. Los informes relacionados con las asignaciones se pueden redirigir a un archivo utilizando la opción output:<filename> . Consulte Debug malloc tool para obtener información detallada sobre la variable MALLOCDEBUG .