Notas de estudio del sistema operativo Linux (ocho) gestión del espacio de tareas

I. Introducción

  Desde el comienzo de este artículo, ingresamos a la parte de memoria del estudio. Primero, seguiré las tareas anteriores para task_structexplicar la estructura de administración del espacio de tareas mm_structy presentaré brevemente el conocimiento relevante de la memoria física y la memoria virtual. Para obtener conocimientos y conceptos básicos detallados, consulte el libro CSAPP. No entraré en demasiados detalles aquí, pero el Aprendizaje basado en la comprensión de su relación cartográfica. En el siguiente artículo, continuaremos presentando la administración de la memoria física y el mapeo de memoria del modo de usuario y el modo de kernel.

2. Conceptos básicos de peinado

  • La arquitectura de CPU, caché, memoria y memoria principal se deriva del hecho de que cuanto más rápido es el dispositivo, más caro, por lo que en aras de la economía (qiong), la arquitectura multicapa está diseñada y la CPU tiene MMU
  • La memoria física es limitada y existen problemas de seguridad en el uso compartido de la memoria física de múltiples procesos, por lo que aparece el diseño de la memoria virtual
  • La memoria virtual está diseñada de acuerdo con la estructura de ELF, y hay partes como montón, área de mapeo, pila, segmento de datos, etc.
  • Teniendo en cuenta la estructura de la memoria virtual, existe una aplicación de pila que es memoria dinámica
  • La memoria virtual asigna un espacio de direcciones separado para cada proceso y lo asigna a la memoria física para su ejecución, por lo que existe un método de asignación para la memoria física y la memoria virtual: página
  • Para administrar la memoria virtual, aparecen tablas de páginas y tablas de páginas de varios niveles
  • Para acelerar el mapeo, apareció el TLB en la CPU
  • Para satisfacer las necesidades de compartir, apareció la memoria compartida en el mapa de memoria
  • Debido a la existencia de fragmentación de la memoria, apareció un diseño de gestión de fragmentos y un recolector de basura

3. Gestión de la memoria de procesos

  Para un proceso, es necesario considerar las diversas estructuras que deben almacenarse en el kernel en modo usuario y modo kernel.

  El modo de usuario incluye

  • Fragmento de código
  • Variable global
  • Cadena constante
  • Pila de funciones, incluidas llamadas a funciones, variables locales, parámetros de funciones, etc.
  • Montón: memoria asignada por malloc, etc.
  • La asignación de memoria, como glibcel glibccódigo de llamada , tiene la forma de archivo, por lo que también debe colocarse en la memoria.

  El modo Kernel incluye

  • Parte del kernel del código
  • Variables globales en el kernel
  • estructura_tarea
  • Pila de kernel
  • También hay memoria asignada dinámicamente en el kernel
  • Tabla de asignación de dirección virtual a dirección física

  El proceso se task_structgestiona en modo kernel y la task_structmemoria tiene las siguientes variables miembro

	struct mm_struct		*mm;
	struct mm_struct		*active_mm;
	/* Per-thread vma caching: */
	struct vmacache			vmacache;

  La mm_structestructura también es más complicada, la presentaremos paso a paso. Primero, echemos un vistazo a la división de direcciones entre el modo kernel y el modo de usuario. Aquí se highest_vm_endalmacena la dirección máxima de la dirección de memoria virtual actual, pero task_sizeel tamaño del modo de usuario.

struct mm_struct {
    
    
......
	unsigned long task_size;	/* size of task vm space */
	unsigned long highest_vm_end;	/* highest vma end address */
......
}

  task_sizeLa definición es la siguiente. De los comentarios, se puede ver que el modo de usuario asigna espacio 3G en la memoria virtual 4G, y debido a que el espacio de 64 bits es enorme, se reserva un área libre entre el modo kernel y el modo de usuario para el aislamiento. El modo de usuario usa solo 47 bits, que es 128TB. El modo kernel también asigna 128TB, que es el bit más alto.

#ifdef CONFIG_X86_32
/*
 * User space process size: 3GB (default).
 */
#define TASK_SIZE    PAGE_OFFSET
#define TASK_SIZE_MAX    TASK_SIZE
/*
config PAGE_OFFSET
        hex
        default 0xC0000000
        depends on X86_32
*/
#else
/*
 * User space process size. 47bits minus one guard page.
*/
#define TASK_SIZE_MAX  ((1UL << 47) - PAGE_SIZE)
#define TASK_SIZE    (test_thread_flag(TIF_ADDR32) ? \
          IA32_PAGE_OFFSET : TASK_SIZE_MAX)
......

3.1 Estructura de la memoria del modo de usuario

  En el modo de usuario, mm_structexisten las siguientes variables miembro

  • mmap_base: La dirección de inicio del mapa de memoria
  • mmap_legacy_base: Indica la dirección base del mapeo, que está fija en 32 bits TASK_UNMAPPED_BASE, y en 64 bits, hay un mecanismo de mapeo aleatorio de direcciones virtuales , por lo que esTASK_UNMAPPED_BASE + mmap_rnd()
  • hiwater_rss: Alto uso de agua de RSS
  • hiwater_vm: Uso de memoria virtual de alto nivel
  • total_vm: Número total de páginas asignadas
  • locked_vm: El número de páginas que están bloqueadas y no se pueden intercambiar
  • pinned_vm: El número de páginas que no se pueden intercambiar ni mover
  • data_vm: El número de páginas que almacenan datos
  • exec_vm: El número de páginas que almacenan archivos ejecutables
  • stack_vm: El número de páginas que almacenan la pila
  • arg_lock: Introducido spin_lockpara proteger el acceso paralelo a las siguientes variables de área
  • start_code 和 end_code: Posición inicial y final del código ejecutable
  • start_data 和 end_data : Posición inicial y posición final de los datos inicializados
  • start_brk : La posición inicial del montón
  • brk : La posición final actual del montón
  • start_stack : La posición inicial de la pila, la posición final de la pila está en el puntero superior del registro.
  • arg_start 和 arg_end : La posición de la lista de parámetros, ubicada en la dirección más alta de la pila.
  • env_start 和 env_end : La ubicación de la variable de entorno, ubicada en la dirección más alta de la pila.
struct mm_struct {
    
    
......    
	unsigned long mmap_base;	/* base of mmap area */
	unsigned long mmap_legacy_base;	/* base of mmap area in bottom-up allocations */    
......
	unsigned long hiwater_rss; /* High-watermark of RSS usage */
	unsigned long hiwater_vm;  /* High-water virtual memory usage */
	unsigned long total_vm;	   /* Total pages mapped */
	unsigned long locked_vm;   /* Pages that have PG_mlocked set */
	atomic64_t    pinned_vm;   /* Refcount permanently increased */
	unsigned long data_vm;	   /* VM_WRITE & ~VM_SHARED & ~VM_STACK */
	unsigned long exec_vm;	   /* VM_EXEC & ~VM_WRITE & ~VM_STACK */
	unsigned long stack_vm;	   /* VM_STACK */    
	spinlock_t arg_lock; /* protect the below fields */
	unsigned long start_code, end_code, start_data, end_data;
	unsigned long start_brk, brk, start_stack;
	unsigned long arg_start, arg_end, env_start, env_end;
	unsigned long saved_auxv[AT_VECTOR_SIZE]; /* for /proc/PID/auxv */    
......
}

  De acuerdo con estas variables miembro, podemos planificar la posición de cada parte en el estado del usuario, pero también necesitamos una estructura para describir los atributos de estas áreas, a sabervm_area_struct

struct mm_struct {
    
    
......    
	struct vm_area_struct *mmap;		/* list of VMAs */
	struct rb_root mm_rb;  
......    
}

  vm_area_structLa definición de estructura específica de es la siguiente: en realidad es una lista doblemente enlazada combinada por vm_nexty vm_prev, es decir, una serie de contenidos vm_area_structpara expresar un proceso en cada área asignada en el modo usuario.

  • vm_startY vm_endexpresa el principio y el final del área del bloque.
  • vm_rbCorrespondiente a un árbol rojo-negro, este árbol rojo-negro combina todo vm_area_structpara una fácil adición, eliminación y búsqueda.
  • rb_subtree_gapAlmacene el intervalo entre el área actual y el área anterior para su posterior asignación.
  • vm_mmSeñale la estructura a la que pertenece la estructuravm_struct
  • vm_page_protGestionar la autoridad de acceso de esta página, vm_flagscomo el bit de marca
  • rbY rb_subtree_last: estructura de árbol de intervalos con posiciones libres
  • ano_vma 和 ano_vma_chain: Mapeo anónimo. El área de memoria virtual se puede asignar a la memoria física oa un archivo. Cuando se asigna a la memoria física, se denomina asignación anónima. Cuando se asigna a un archivo, debe vm_fileespecificar el archivo asignado y vm_pgoffalmacenar el desplazamiento.
  • vm_opts: Un puntero de función a la estructura, utilizado para procesar la estructura
  • vm_private_data: Almacenamiento de datos privados
/*
 * This struct defines a memory VMM memory area. There is one of these
 * per VM-area/task.  A VM area is any part of the process virtual memory
 * space that has a special rule for the page-fault handlers (ie a shared
 * library, the executable area etc).
 */
struct vm_area_struct {
    
    
	/* The first cache line has the info for VMA tree walking. */
	unsigned long vm_start;		/* Our start address within vm_mm. */
	unsigned long vm_end;		/* The first byte after our end address
					   within vm_mm. */
	/* linked list of VM areas per task, sorted by address */
	struct vm_area_struct *vm_next, *vm_prev;
	struct rb_node vm_rb;
	/*
	 * Largest free memory gap in bytes to the left of this VMA.
	 * Either between this VMA and vma->vm_prev, or between one of the
	 * VMAs below us in the VMA rbtree and its ->vm_prev. This helps
	 * get_unmapped_area find a free area of the right size.
	 */
	unsigned long rb_subtree_gap;
	/* Second cache line starts here. */
	struct mm_struct *vm_mm;	/* The address space we belong to. */
	pgprot_t vm_page_prot;		/* Access permissions of this VMA. */
	unsigned long vm_flags;		/* Flags, see mm.h. */
	/*
	 * For areas with an address space and backing store,
	 * linkage into the address_space->i_mmap interval tree.
	 */
	struct {
    
    
		struct rb_node rb;
		unsigned long rb_subtree_last;
	} shared;
	/*
	 * A file's MAP_PRIVATE vma can be in both i_mmap tree and anon_vma
	 * list, after a COW of one of the file pages.	A MAP_SHARED vma
	 * can only be in the i_mmap tree.  An anonymous MAP_PRIVATE, stack
	 * or brk vma (with NULL file) can only be in an anon_vma list.
	 */
	struct list_head anon_vma_chain; /* Serialized by mmap_sem & page_table_lock */
	struct anon_vma *anon_vma;	/* Serialized by page_table_lock */
	/* Function pointers to deal with this struct. */
	const struct vm_operations_struct *vm_ops;
	/* Information about our backing store: */
	unsigned long vm_pgoff;		/* Offset (within vm_file) in PAGE_SIZE
					   units */
	struct file * vm_file;		/* File we map to (can be NULL). */
	void * vm_private_data;		/* was vm_pte (shared mem) */
	atomic_long_t swap_readahead_info;
#ifndef CONFIG_MMU
	struct vm_region *vm_region;	/* NOMMU mapping region */
#endif
#ifdef CONFIG_NUMA
	struct mempolicy *vm_policy;	/* NUMA policy for the VMA */
#endif
	struct vm_userfaultfd_ctx vm_userfaultfd_ctx;
} __randomize_layout;

  Para a mm_struct, vm_area_structse carga su archivo ELF de muchos , es decir, load_elf_binary()cuando se carga el archivo build . Después de que la función analiza el formato de archivo ELF, establecerá el mapa de memoria, que incluye principalmente

  • Llamar setup_new_exec, configurar el área del mapa de memoriammap_base
  • Llamadas setup_arg_pages, configura la pila vm_area_struct, se proporciona mm->arg_startun punto de la parte inferior de la pila, current->mm->start_stackes la parte inferior de la pila
  • elf_map Asignará parte del código en el archivo ELF a la memoria
  • set_brkEl montón vm_area_structestá configurado current->mm->start_brk = current->mm->brky el interior está configurado , es decir, el montón todavía está vacío
  • load_elf_interpEl dependiente somapeado en memoria área de memoria mapeada
static int load_elf_binary(struct linux_binprm *bprm)
{
    
    
......
    setup_new_exec(bprm);
......
	/* Do this so that we can load the interpreter, if need be.  We will
	   change some of these later */    
    retval = setup_arg_pages(bprm, randomize_stack_top(STACK_TOP),
         executable_stack);
......
    error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt,
        elf_prot, elf_flags, total_size);
......
	/* Calling set_brk effectively mmaps the pages that we need
	 * for the bss and break sections.  We must do this before
	 * mapping in the interpreter, to make sure it doesn't wind
	 * up getting placed where the bss needs to go.
	 */    
    retval = set_brk(elf_bss, elf_brk, bss_prot);
......
    elf_entry = load_elf_interp(&loc->interp_elf_ex,
              interpreter,
              &interp_map_addr,
              load_bias, interp_elf_phdata);
......
    current->mm->end_code = end_code;
    current->mm->start_code = start_code;
    current->mm->start_data = start_data;
    current->mm->end_data = end_data;
    current->mm->start_stack = bprm->p;
......
}

3.2 estructura de estado del kernel

  Debido a la gran brecha entre los sistemas de 32 y 64 bits, existen algunas diferencias en la estructura. Discutimos la estructura de los dos por separado aquí.

3.2.1 Estructura del modo kernel de 32 bits

  El espacio virtual en el modo kernel es independiente del proceso, es decir, después de que todos los procesos ingresan al kernel a través de llamadas al sistema, el espacio de direcciones virtuales que ven es el mismo. La siguiente figura muestra el diagrama de distribución del espacio virtual del estado del kernel de 32 bits.

img
  1. Área de mapeo directo

    El primer 896M es un área de mapeo directo, que se utiliza para mapeo directo con memoria física. Reste 3G de la dirección de la memoria virtual para obtener la ubicación de la memoria física correspondiente. En el kernel, hay dos macros:

  • __pa(vaddr)Devuelve la dirección vaddrfísica asociada a la dirección virtual ;

  • __va(paddr)Cálculo de la dirección física correspondiente a la paddrdirección virtual.

  El acceso a esta parte de la dirección virtual también se realiza a modo de paginación, pero la dirección de la tabla de página es relativamente simple y la correspondencia uno a uno es suficiente.

  Cuando se inicia el sistema, el primer 1M de la memoria física ya está ocupado. El segmento de código del kernel se carga desde 1M, y luego las variables globales del kernel, BSS, etc., también se cubren en ELF. De esta forma, los segmentos de código del núcleo, las variables globales y el BSS también se asignarán al espacio de direcciones virtuales después de 3G. Se puede ver el diseño específico de la memoria física /proc/iomem, y el específico será diferente debido al sistema y la configuración de cada persona.

  1. alta_memoria

  El nombre de memoria de alta gama proviene de la división del espacio de direcciones físicas en tres partes en la arquitectura x86: ZONE_DMA, ZONE_NORMAL y ZONE_HIGHMEM. ZONE_HIGHMEM tiene mucha memoria.

  La memoria de gama alta es el nombre con el que el módulo de administración de memoria mira la memoria física, que se refiere al área por encima del área de mapeo directo del 896M. ** A excepción del módulo de administración de memoria en el kernel, el resto opera en direcciones virtuales. ** El módulo de gestión de memoria manipula directamente la dirección física y realiza la asignación y asignación de direcciones virtuales. El significado de su existencia es acceder al espacio de memoria física infinita desde el espacio limitado del kernel del sistema de 32 bits: pedir prestado este espacio de direcciones lógicas, crear una asignación a la memoria física a la que desea acceder (es decir, llenar la tabla de la página del kernel) y usarla temporalmente por un tiempo Y devuélvalo después de su uso.

  1. Espacio de mapeo dinámico del kernel (asignación de memoria no contigua)

  En VMALLOC_STARTy VMALLOC_ENDllamar al mapeo dinámico del kernel entre la región del espacio, mallocse vmallocpuede aplicar un proceso correspondiente a la memoria de la aplicación en modo usuario como en el modo kernel . El modo kernel tiene una gestión de tabla de páginas separada, separada del modo de usuario.

  1. Área de mapeo de kernel permanente (mapeo de kernel permanente)

  PKMAP_BASEAl FIXADDR_STARTespacio del kernel se le llama mapeo persistente entre el rango de direcciones de 4G-8M a 4G-4M. Usando la alloc_pages()función cuando la memoria física en la struct pageestructura resultante de la memoria superior , se puede llamar kmapa mapear a esta región. Debido a que el número de asignaciones permanentes permitidas es limitado, cuando la memoria de gama alta ya no es necesaria, la asignación debe desmapearse, lo que se puede realizar mediante kunmap()funciones.

  1. Área de mapeo fija

  FIXADDR_STARTEl FIXADDR_TOP(0xFFFF F000)espacio, llamado área cartográfica fija, se utiliza principalmente para satisfacer necesidades especiales.

  1. Mapeo temporal del kernel

  El mapeo temporal del kernel se pasa kmap_atomice kunmap_atomicimplementa, y se usa principalmente para operaciones cuando se requiere escribir en la memoria física o en la memoria principal, como cuando se escriben archivos.

3.2.2 Estructura del modo kernel de 64 bits

  Debido al enorme espacio en el modo kernel de 64 bits, no es necesario planificar con cuidado como en el modo de 32 bits, y muchas áreas libres se dividen directamente para su protección. La estructura se muestra en la figura siguiente.

img
  • Comenzar desde 0xffff800000000000 es parte del kernel, pero al principio hay un área de espacio de 8T.
  • Desde el __PAGE_OFFSET_BASE(0xffff880000000000)espacio de direcciones virtuales que comienza 64T es un mapeo directo del área, que se resta PAGE_OFFSETes la dirección física. En la mayoría de los casos, el mapeo entre direcciones virtuales y direcciones físicas aún se mapeará estableciendo una tabla de páginas.
  • Desde VMALLOC_START(0xffffc90000000000)el principio hasta el VMALLOC_END(0xffffe90000000000)espacio de 32T es dar vmallocel.
  • Desde el VMEMMAP_START(0xffffea0000000000)espacio 1T para almacenar la descripción física inicial de la estructura struct pagede la página.
  • A partir de __START_KERNEL_map(0xffffffff80000000)512M, el segmento de código del kernel se utiliza para almacenar variables globales y, por lo tanto, el BSS. Esto corresponde a la posición inicial de la memoria física menos la __START_KERNEL_mapposibilidad de obtener la dirección de la memoria física. Esto es un poco similar al área de mapeo directo, pero no es contradictorio, porque hay un área vacía de 8T antes del área de mapeo directo, que ha pasado hace mucho tiempo la ubicación donde se carga el código del kernel en la memoria física.

para resumir

  Este artículo analiza con más detalle la estructura del modo de usuario y el modo de kernel en la memoria, a partir de lo cual podemos comenzar a analizar la gestión y mapeo de la memoria posteriormente.

Información de código

[1] linux / include / linux / mm_types.h

Referencia

[1] wiki

[2] elixir.bootlin.com/linux

[3] woboq

[4] Interior de Linux

[5] Conocimiento profundo del kernel de Linux

[6] El arte del diseño del kernel de Linux

[7] Geek Time habla sobre el sistema operativo Linux

Supongo que te gusta

Origin blog.csdn.net/u013354486/article/details/106960441
Recomendado
Clasificación