Gestión de memoria de Linux (1): descripción general

1. Disposición de la memoria de proceso de Linux

2. ¿Por qué limitar el tamaño de la pila?

  2.1 Pila de procesos

  2.2 Pila de hilos    

3. Funciones relacionadas con el diseño de la memoria del sistema operativo

  3.1 Funciones relacionadas con la operación del montón

  3.2 Funciones relacionadas con la operación del área de mapeo de Mmap

4. Método de gestión de la memoria

  4.1. Programa de gestión de memoria estilo C

  4.2. Gestión de memoria agrupada

  4.3. Recuento de referencias

  4.4. Recolección de basura

5. Programa común de gestión de memoria C


    La gestión de la memoria no es más que tres niveles, la capa del programa de usuario, la capa de la biblioteca en tiempo de ejecución C y la capa del kernel. Allocator es el módulo de administración de memoria de la biblioteca en tiempo de ejecución de C. Responde a la solicitud de asignación del usuario, solicita memoria del kernel y luego la devuelve al programa del usuario. Para mantener una asignación eficiente, el asignador generalmente preasigna una parte de la memoria más grande que la solicitud del usuario y administra esta memoria a través de un algoritmo determinado. Para cumplir con los requisitos de asignación de memoria del usuario, la memoria libre del usuario no se devuelve inmediatamente a la operación system Por el contrario, el asignador administrará el espacio libre que se libera para cumplir con los requisitos futuros de asignación de memoria del usuario. Es decir, el asignador no solo necesita administrar el bloque de memoria asignado, sino que también debe administrar el bloque de memoria libre, cuando responder a los requisitos de asignación de usuarios En este momento, el asignador primero encontrará una memoria adecuada en el espacio libre para el usuario y asignará una nueva memoria cuando no se pueda encontrar en el espacio libre.

1. Disposición de la memoria de proceso de Linux

    Cuando el sistema Linux carga el archivo de programa en formato elf, llamará al cargador para cargar cada segmento del archivo ejecutable en el espacio comenzando desde una determinada dirección (la dirección de carga depende del editor de enlaces (ld) y el número de direcciones de máquina, en una máquina de 32 bits, es 0x8048000, que está a 128M). Como se muestra abajo:

       

    Tomando una máquina de 32 bits como ejemplo, la sección .text se carga primero , luego la sección .data y finalmente la sección .bss . Esto puede verse como el espacio de inicio del programa. La última dirección a la que puede acceder el programa es 0xbfffffff, es decir, a la dirección 3G. El espacio 1G por encima de 3G es utilizado por el kernel y las aplicaciones no pueden acceder directamente a él.

    La pila del programa de aplicación comienza desde la dirección más alta y crece hacia abajo. El espacio entre la sección .bss y la pila es libre. El espacio libre se divide en dos partes, una es el montón y la otra es el área de mapeo mmap. El área de mapeo de mmap generalmente comienza desde TASK_SIZE / Start at 3, pero en diferentes kernels y máquinas de Linux, la posición inicial del área de mmap es generalmente diferente. Los usuarios pueden utilizar libremente las áreas Heap y mmap, pero no están asignadas al espacio de memoria al principio y son inaccesibles. Antes de solicitar al kernel que asigne el espacio, el acceso a este espacio provocará una falla de segmentación. El programa de usuario puede usar directamente la llamada al sistema para administrar el área de mapeo de heap y mmap, pero más a menudo el programa usa las funciones malloc () y free () proporcionadas por el lenguaje C para asignar y liberar memoria dinámicamente. El área de pila es la única área de memoria a la que los usuarios pueden acceder sin mapeo. Esta es también la base para los ataques que utilizan el desbordamiento de pila.

    El diseño de la figura anterior es el diseño de memoria de proceso predeterminado antes del kernel de Linux 2.6.7 . El área de mmap y el área de pila crecen relativamente, lo que significa que el montón tiene solo 1 GB de espacio de direcciones virtuales disponible. Si continúa creciendo, entrará en el área de mapeo mmap Obviamente no es lo que queremos. Esto se debe a la limitación del espacio de direcciones de 32 modos, por lo que el kernel introduce otra forma de diseño de espacio de direcciones virtual, que se presentará más adelante. Pero para los sistemas de 64 bits, que proporcionan un gran espacio de direcciones virtuales, este diseño es bastante bueno. Después del kernel de Linux 2.6.7, la distribución de la memoria del proceso se muestra en la siguiente figura:

    

    Como puede ver en la figura anterior, la pila se extiende de arriba a abajo y la pila está delimitada. El montón se expande hacia arriba desde la parte inferior, el área de mapeo de mmap se expande desde arriba hacia abajo, y el área de mapeo de mmap y el montón se expanden relativamente hasta que se agota el área restante en el espacio de direcciones virtuales. Esta estructura es conveniente para que la biblioteca de tiempo de ejecución de C use el área de mapeo mmap y el montón para la distribución de memoria. El diseño de la figura anterior se introdujo después del kernel 2.6.7 , que es el diseño de memoria predeterminado del proceso en modo de 32 bits.

    ¿Cuál es la posición inicial de cada área en el modo de 64 bits? Para el sistema AMD64, el diseño de memoria adopta el diseño de memoria clásico, la dirección inicial del texto es 0x0000000000400000, el montón crece hacia arriba inmediatamente después del segmento BSS y la posición inicial de El área de mapeo de mmap generalmente se establece en TASK_SIZE / 3.

#define TASK_SIZE_MAX ((1UL << 47) - PAGE_SIZE)

#define TASK_SIZE  (test_thread_flag(TIF_IA32) ? IA32_PAGE_OFFSET : TASK_SIZE_MAX)

#define STACK_TOP TASK_SIZE

#define TASK_UNMAPPED_BASE (PAGE_ALIGN(TASK_SIZE/3))

    El cálculo muestra que la dirección del área de inicio de mmap es 0x00002AAAAAAAA000, y la dirección de la parte superior de la pila es 0x00007FFFFFFFF000. La siguiente figura muestra el diseño de la memoria de proceso de 64 bits:

     

    La figura anterior es el diseño de memoria predeterminado del proceso de Linux en X86_64. Este es solo un diagrama esquemático. Bajo la configuración predeterminada del kernel actual, el área de mapeo de pila y mmap del proceso no comienza desde una dirección fija, y el El valor es diferente cada vez que se inicia, así es como el programa cambia aleatoriamente la configuración de estos valores al inicio, lo que dificulta el ataque mediante desbordamientos de búfer. Por supuesto, también puede iniciar el área de mapeo de pila y mmap del proceso desde una posición fija, simplemente establezca la variable global randomize_va_space en 0, y el valor predeterminado de esta variable es 1. Los usuarios pueden desactivar esta función configurando / proc / sys / kernel / randomize_va_space, o usar el siguiente comando:

sudo sysctl -w kernel.randomize_va_space=0

2. ¿Por qué limitar el tamaño de la pila?

2.1 Pila de procesos

    El compilador y el enlazador calculan el tamaño inicial de la pila de procesos, pero el tamaño en tiempo real de la pila no es fijo. El kernel de Linux hará crecer dinámicamente el área de la pila de acuerdo con la situación de apilamiento (de hecho, significa agregar un nueva tabla de páginas). Pero no significa que el área de la pila pueda crecer indefinidamente, también tiene un límite máximo  RLIMIT_STACK (generalmente 8M), y podemos  ulimit verificar o cambiar  RLIMIT_STACK el valor a través de él.

2.2 Pila de hilos    

   Desde la perspectiva del kernel de Linux, en realidad no tiene el concepto de subprocesos. Linux implementa todos los subprocesos como procesos y unifica los subprocesos y procesos en task_struct de forma indiscriminada. Un hilo solo se considera un proceso que comparte algunos recursos con otros procesos, y si se comparte o no el espacio de direcciones es casi la única diferencia entre un proceso y el llamado hilo en Linux. Cuando se crea el hilo, se agrega la marca CLONE_VM, de modo que el descriptor de memoria del hilo apunte directamente al descriptor de memoria del proceso padre. Aunque el espacio de direcciones de un hilo es el mismo que el de un proceso, existen algunas diferencias en la pila de su espacio de direcciones. Para el proceso de Linux o el hilo principal, la pila se genera durante la bifurcación, que en realidad copia la dirección del espacio de pila del padre, y luego copia en escritura (vaca) y crece dinámicamente. Sin embargo, para los subprocesos generados por el subproceso principal, la pila ya no será así, sino que se arreglará de antemano. Cuando se crea el subproceso, la llamada al sistema mmap se utiliza para asignar la pila al subproceso. La dirección de inicio y el tamaño de la pila de subprocesos se almacenan en pthread_attr_t.

    La pila debe almacenarse en una ubicación de memoria contigua. Esto significa que la pila no se puede asignar aleatoriamente según sea necesario, pero al menos se debe reservar una dirección virtual para esto. Cuanto mayor sea el espacio de direcciones virtuales reservado, menos subprocesos se pueden ejecutar . Por ejemplo, las aplicaciones de 32 bits suelen tener 2 GB de espacio de direcciones virtuales. Esto significa que si el tamaño de la pila es de 2 MB (el valor predeterminado en pthreads), se pueden crear hasta 1024 subprocesos. Para aplicaciones como servidores web, esto puede ser pequeño. Aumentar el tamaño de la pila a 100 MB (es decir, reservar 100 MB, pero no necesariamente asignar 100 MB a la pila inmediatamente) limitará el número de subprocesos a alrededor de 20, incluso para aplicaciones GUI simples. Una pregunta interesante es por qué todavía tenemos esta limitación en las plataformas de 64 bits. No sé la respuesta, pero supongo que la gente está acostumbrada a algunas "mejores prácticas de pila": tenga cuidado de asignar objetos enormes en la pila y aumente manualmente el tamaño de la pila si es necesario. Por lo tanto, a nadie le ha resultado útil agregar soporte de pila "enorme" en una plataforma de 64 bits.

3. Funciones relacionadas con el diseño de la memoria del sistema operativo

    Como se mencionó en la sección anterior, el área de mapeo de heap y mmap es un espacio de memoria virtual que se puede proporcionar a los programas de usuario. ¿Cómo obtener la memoria en esta área? El sistema operativo proporciona llamadas al sistema relacionadas para completar el trabajo relacionado. Para el funcionamiento del montón, el sistema operativo proporciona la función brk () y la biblioteca de tiempo de ejecución de C proporciona la función sbrk (); para el funcionamiento del área de mapeo mmap, el sistema operativo proporciona mmap () y munmap () funciones. sbrk (), brk () o mmap () pueden usarse para agregar memoria virtual adicional a nuestro proceso. Glibc también utiliza estas funciones para solicitar memoria virtual del sistema operativo.

    Hay un concepto muy importante que mencionar aquí, la asignación retardada de memoria, el mapeo físico de esta dirección solo se establece cuando se accede a una dirección, esta es una de las ideas básicas de la gestión de memoria de Linux. Cuando el usuario solicita memoria, el kernel de Linux solo asigna un área lineal (es decir, memoria virtual), pero no asigna memoria física real; solo cuando el usuario usa esta memoria, el kernel le asignará páginas físicas específicas. usuario, en este momento, ocupa una memoria física preciosa. El kernel libera la página física liberando el área lineal, encontrando la página física correspondiente y soltándola por completo.

3.1 Funciones relacionadas con la operación del montón

    Hay dos funciones principales de operación de Heap, brk () es una llamada al sistema y sbrk () es una función de biblioteca C. Las llamadas al sistema suelen proporcionar una función mínima, mientras que las funciones de biblioteca suelen proporcionar funciones más complejas. La familia de funciones malloc de Glibc (realloc, calloc, etc.) llama a la función sbrk () para mover el límite inferior del segmento de datos. La función sbrk () mapea el espacio de direcciones virtuales a la memoria bajo la administración del kernel para que lo use el función malloc (). En la estructura de datos del kernel mm_struct:

  • start_code y end_code son las direcciones de inicio y finalización del segmento de código de proceso;
  • start_data y end_data son las direcciones de inicio y finalización del segmento de datos de proceso;
  • start_stack es la dirección de inicio del segmento de la pila de procesos;
  • start_brk es la dirección de inicio de la asignación de memoria dinámica del proceso (la dirección de inicio del montón),
  • brk es la última dirección actual del montón, que es la dirección final actual de la asignación de memoria dinámica.

    La función básica de la asignación de memoria dinámica en lenguaje C es malloc (), y la implementación en Linux es a través de la llamada al sistema brk del kernel. brk () es una llamada al sistema muy simple, que simplemente cambia el valor de la variable miembro brk de la estructura mm_struct. Las definiciones de estas dos funciones son las siguientes:

#include <unistd.h>

int brk(void *addr);

void *sbrk(intptr_t increment);

    Cabe señalar que cuando el incremento del parámetro de sbrk () es 0, sbrk () devuelve el valor de brk actual del proceso. Cuando el incremento es positivo, el valor de brk se expande, y cuando el incremento es negativo, el valor de brk es contratado.    

3.2 Funciones relacionadas con la operación del área de mapeo de Mmap

    La función mmap () mapea un archivo u otro objeto en la memoria. El archivo se asigna a varias páginas. Si el tamaño del archivo no es la suma de los tamaños de todas las páginas, se borrará el espacio no utilizado de la última página. munmap realiza la operación opuesta y elimina el mapeo de objetos en un área de dirección específica. La definición de la función es la siguiente:

#include <sys/mman.h>

void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset); 
// 若映射成功则返回映射区的内存起始地址,否则返回MAP_FAILED(-1),错误原因存于errno 中。

int munmap(void *addr, size_t length);

   parámetro:

  • addr: apunte a la dirección de inicio de la memoria que se va a mapear, normalmente establecida en NULL, lo que significa que el sistema selecciona automáticamente la dirección y devuelve la dirección después de que el mapeo sea exitoso;
  • longitud: la longitud del área cartográfica;
  • prot: El modo de protección del área mapeada, que no puede entrar en conflicto con el modo abierto del archivo. Es uno de los siguientes valores, que pueden combinarse razonablemente con la operación o. Las siguientes banderas se utilizan principalmente en Ptmalloc:
  • PROT_EXEC // El contenido de la página se puede ejecutar, no se usa en ptmalloc
  • PROT_READ // El contenido de la página se puede leer, ptmalloc usa directamente mmap para asignar memoria y establecer esta bandera cuando regresa al usuario inmediatamente
  • PROT_WRITE // La página se puede escribir, ptmalloc usa directamente mmap para asignar memoria y establecer esta bandera cuando regresa al usuario inmediatamente
  • PROT_NONE // La página es inaccesible. Ptmalloc usa mmap para "vender al por mayor" una parte de la memoria al sistema para su administración. Establecer esta bandera
  • banderas: especifique el tipo de objeto de mapeo, si las opciones de mapeo y la página de mapeo se pueden compartir. Su valor puede ser una combinación de uno o más de los siguientes bits
  • MAP_FIXED // Utilice la dirección de inicio de mapeo especificada. Si el área de memoria especificada por los parámetros start y len se superpone al espacio de mapeo existente, la parte superpuesta se descartará. Si la dirección de inicio especificada no está disponible, la operación fallará. Y la dirección de inicio debe estar dentro del límite de la página. Ptmalloc establece esta bandera cuando recupera memoria "al por mayor" del sistema.
  • MAP_PRIVATE // Cree una asignación privada para copiar al escribir. La escritura del área de memoria no afectará al archivo original. Esta bandera y las banderas anteriores son mutuamente excluyentes, solo se puede usar una de ellas. Ptmalloc establece este indicador cada vez que se llama a mmap.
  • MAP_NORESERVE // No reserve espacio de intercambio para este mapeo. Cuando se reserva el espacio de intercambio, se puede garantizar la modificación del área de mapeo. Cuando el espacio de intercambio no está reservado y la memoria es insuficiente, la modificación del área de mapeo provocará una señal de violación de segmento. Ptmalloc establece esta bandera cuando la memoria "al por mayor" bloquea el sistema.
  • MAP_ANONYMOUS // Mapeo anónimo, el área de mapeo no está asociada a ningún archivo. Ptmalloc establece este indicador cada vez que se llama a mmap.
  • fd: una palabra de descripción de archivo válida. Si MAP_ANONYMOUS está configurado, por problemas de compatibilidad, su valor debe ser -1. Algunos sistemas no admiten la asignación de memoria anónima, puede usar fopen para abrir el archivo / dev / zero y luego asignar el archivo, también puede lograr el efecto de la asignación de memoria anónima.
  • offset: El punto de inicio del contenido del objeto mapeado, generalmente establecido en 0, lo que significa que el correspondiente comienza desde el frente del archivo. El offset debe ser un múltiplo entero del tamaño de la página.

4. Método de gestión de la memoria

4.1. Programa de gestión de memoria estilo C

    El programa de administración de memoria estilo C implementa principalmente funciones malloc () y free (). El programa de administración de memoria agrega principalmente memoria virtual adicional llamando al proceso brk () o mmap (). Doug Lea Malloc, ptmalloc, BSD malloc, Hoard, TCMalloc pertenecen a este tipo de programa de gestión de memoria.

    El administrador de memoria basado en malloc () todavía tiene muchas deficiencias, sin importar qué programa de asignación se utilice. Para aquellos programas que necesitan mantener un almacenamiento a largo plazo, usar malloc () para administrar la memoria puede ser muy decepcionante. Si hay una gran cantidad de referencias de memoria no fijadas, a menudo es difícil saber cuándo se publicarán. La memoria cuya vida útil está limitada a la función actual es muy fácil de administrar, pero para la memoria cuya vida útil excede este rango, es mucho más difícil administrar la memoria. Debido al problema de la gestión de la memoria, muchos programas tienden a utilizar sus propias reglas de gestión de la memoria.

4.2. Gestión de memoria agrupada

    La agrupación de memoria es un método de gestión de semi-memoria. La reserva de memoria ayuda a ciertos programas a realizar una gestión automática de la memoria, que pasan por algunas etapas específicas y cada etapa tiene memoria asignada a una etapa específica del proceso. Por ejemplo, muchos procesos de servidor web asignan mucha memoria para cada conexión; la vida útil máxima de la memoria es la vida útil de la conexión actual. Apache usa memoria agrupada para dividir su conexión en varias etapas, cada etapa tiene su propia agrupación de memoria. Al final de cada fase, toda la memoria se libera a la vez.

    En la administración de memoria agrupada, cada asignación de memoria especificará una agrupación de memoria desde la cual asignar memoria. Cada grupo de memoria tiene una vida útil diferente. En Apache, hay un grupo de memoria cuya duración es el tiempo de vida del servidor, otro grupo de memoria cuya duración es el tiempo de vida de la conexión y un grupo cuya duración es el tiempo de vida de la solicitud, y hay otros grupos de memoria. Por lo tanto, si mi serie de funciones no genera datos más largos que la duración de la conexión, entonces puedo asignar completamente la memoria del grupo de conexiones y saber que la memoria se liberará automáticamente cuando finalice la conexión. Además, hay algunas implementaciones que permiten el registro de funciones de limpieza, que se pueden llamar justo antes de que se borre el grupo de memoria para completar todas las demás tareas que deben completarse antes de que se limpie la memoria (similar a los destructores orientados a objetos) .

    Las ventajas de utilizar la asignación de memoria agrupada son las siguientes:

  • La aplicación simplemente puede administrar la memoria.
  • La asignación y recuperación de memoria es más rápida porque se realiza en un grupo cada vez. La asignación se puede completar en O (1) tiempo, y el tiempo requerido para liberar el grupo de memoria es aproximadamente el mismo (en realidad O (n) tiempo, pero en la mayoría de los casos se dividirá por un factor grande para convertirlo en O (1) ))).
  • Los grupos de manejo de errores se pueden asignar por adelantado para que el programa pueda recuperarse cuando se agote la memoria convencional.
  • Hay implementaciones estándar muy fáciles de usar.

   Las desventajas de la memoria agrupada son:

  • El grupo de memoria solo es adecuado para programas cuyas operaciones se pueden organizar.
  • Los grupos de memoria generalmente no funcionan bien con bibliotecas de terceros.
  • Si la estructura del programa cambia, debe modificar el grupo de memoria, lo que puede llevar a un rediseño del sistema de administración de memoria.
  • Debe recordar desde qué grupo necesita realizar la asignación. Además, si algo sale mal aquí, será difícil capturar el grupo de memoria.

4.3. Recuento de referencias

    En el recuento de referencias, todas las estructuras de datos compartidas tienen un campo que contiene el número de veces que la estructura está activa actualmente. Al pasar un puntero a una estructura de datos a un programa, el programa incrementa el recuento de referencias en 1. En esencia, le dice a la estructura de datos en cuántas ubicaciones se almacenan. Luego, cuando el proceso termine de usarlo, el programa disminuirá el recuento de referencias en uno. Una vez finalizada esta acción, también comprueba si el recuento se ha reducido a cero. Si es así, liberará la memoria.

    En lenguajes de alto nivel como Java y Perl, el recuento de referencias se usa ampliamente para la gestión de la memoria. En estos idiomas, el recuento de referencias se maneja automáticamente por el idioma, por lo que no tiene que preocuparse por ello en absoluto a menos que desee escribir módulos de extensión. Dado que todo debe contarse como referencia, esto tendrá algún impacto en la velocidad, pero mejora en gran medida la seguridad y conveniencia de la programación.

    Los siguientes son los beneficios del recuento de referencias:

  • Sencillo de implementar.
  • Fácil de usar.
  • Dado que la referencia es parte de la estructura de datos, tiene una buena ubicación de caché.

    También tiene sus defectos:

  • Es necesario que nunca olvide llamar a la función de recuento de referencias.
  • La estructura que forma parte de la estructura de datos cíclicos no se puede liberar.
  • Ralentice la asignación de casi todos los punteros.
  • Aunque los objetos utilizados se cuentan por referencias, cuando se utiliza el manejo de excepciones (como try o setjmp () / longjmp ()), debe adoptar otros enfoques.
  • Se requiere memoria adicional para manejar referencias.
  • El recuento de referencias ocupa la primera posición en la estructura, y es esta posición a la que se puede acceder más rápidamente en la mayoría de las máquinas.
  • Es más lento y más difícil de usar en un entorno multiproceso.

4.4. Recolección de basura

    La recolección de basura es la detección y eliminación automática de objetos de datos que ya no se utilizan. El recolector de basura generalmente se ejecuta cuando la memoria disponible cae por debajo de un umbral específico. Por lo general, utilizan un conjunto de datos "básicos" conocidos por el programa (datos de pila, variables globales, registros) como punto de partida. Luego, intentan rastrear cada dato conectado a él a través de estos datos. Lo que el recolector encuentra son datos útiles, lo que no encuentra es basura, que puede ser destruida y reutilizada. Para administrar la memoria de manera efectiva, muchos tipos de recolectores de basura necesitan conocer la planificación de punteros dentro de la estructura de datos, por lo tanto, para ejecutar correctamente el recolector de basura, deben ser parte del lenguaje en sí.

    Algunas ventajas de la recolección de basura:

  • Nunca se preocupe por la doble liberación de memoria o el ciclo de vida de los objetos.
  • Con algunos recopiladores, puede utilizar la misma API que para la asignación normal.

    Sus desventajas incluyen:

  • Cuando utiliza la mayoría de los colectores, no puede interferir con el momento de liberar la memoria.
  • En la mayoría de los casos, la recolección de basura es más lenta que otras formas de administración de memoria.
  • Los defectos causados ​​por errores de recolección de basura son difíciles de depurar.
  • Si olvida establecer el puntero que ya no se usa en nulo, todavía habrá una pérdida de memoria.

5. Programa común de gestión de memoria C

  • Doug Lea Malloc:

    Doug Lea Malloc es en realidad un conjunto completo de procedimientos de asignación, incluidos los procedimientos de asignación originales de Doug Lea, los procedimientos de asignación de GNU libc y ptmalloc. El programa de asignación de Doug Lea agrega un índice, lo que hace que la búsqueda sea más rápida y puede combinar varios bloques no utilizados en un bloque grande. También admite el almacenamiento en caché para que la memoria lanzada recientemente se pueda reutilizar más rápidamente. ptmalloc es una versión extendida de Doug Lea Malloc que admite subprocesos múltiples.

  • BSD Malloc:

    BSD Malloc es una implementación lanzada con 4.2 BSD e incluida en FreeBSD Este asignador puede asignar objetos de un grupo de objetos de cierto tamaño por adelantado. Tiene algunas clases de tamaño para el tamaño de los objetos El tamaño de estos objetos es una potencia de 2 menos una constante. Entonces, si solicita un objeto de un tamaño determinado, simplemente asigna una clase de tamaño coincidente. Esto proporciona una implementación rápida, pero puede desperdiciar memoria.

  • Acumular:

    El objetivo de escribir Hoard es hacer que la asignación de memoria sea muy rápida en un entorno de subprocesos múltiples. Por tanto, su construcción se centra en el uso de bloqueos, para que todos los procesos no tengan que esperar para asignar memoria. Puede acelerar significativamente los procesos de subprocesos múltiples que realizan una gran cantidad de asignación y recuperación.

  • TCMalloc:

    tcmalloc es un asignador de memoria desarrollado por Google, que se utiliza para la asignación de memoria en Golang y Chrome. Optimice eficazmente los problemas existentes en ptmalloc. Por supuesto, se ha pagado un precio por esto. Haga clic aquí para ver la implementación específica de tcmalloc.

  • Jemalloc:

    jemalloc es lanzado por Facebook y actualmente se usa ampliamente en servicios como Firefox, servidor de Facebook y Android 5.0. La mayor ventaja de jemalloc es su poderosa capacidad de asignación de múltiples núcleos / múltiples subprocesos. En términos de arquitectura de hardware de computadora moderna, el mayor cuello de botella ya no es la capacidad de memoria o la velocidad de la CPU, sino la contención de bloqueo (contención de bloqueo) en múltiples core / multi-thread Porque independientemente del número de núcleos de CPU, generalmente hay solo una copia de memoria. Se puede decir que si la memoria es lo suficientemente grande, cuanto mayor sea el número de núcleos de CPU y más subprocesos de programa, más rápido la velocidad de asignación de jemalloc.

referencia:

    "Análisis del código fuente de Glibc Memory Management Ptmalloc2"

Supongo que te gusta

Origin blog.csdn.net/MOU_IT/article/details/115273132
Recomendado
Clasificación