Linux Kernel Memory Management

Martin Děcký

1. listopadu 2004

Obsah

Fyzická paměť

Virtuální paměť (z pohledu kernelu)

Způsoby alokace paměti

Detekce fyzické paměti

platformově závislé

i386: arch/i386/boot/setup.S

ještě v reálném módu

data na adresách 0x90000 – 0x901FF

int 15h, AX=0xE820

informace o paměťových regionech (ACPI memory map)

čte se prvních 32 záznamů

záznamy:

8B	base address

8B	length

4B	range type

0x01	available memory

0x02	not available (ROM, HW mapped mem., etc.)

0x03	ACPI memory

0x04	ACPI NVS memory

Detekce fyzické paměti (2)

int 15h, AX=0xE801

velikost paměti v jednotkách 1 KB (pro 0 – 16 MB), resp. 64 KB (> 16 MB)

int 15h, AX=0x8800

failback, 1 KB jednotky, max. 64 MB (někdy jen 16MB)

parametr kernelu

mem=128m

Paměťové zóny

rozdělení fyzické paměti

význam zón platformově závislý

DMA

NORMAL

HIGH

i386

arch/i386/mm/init.c

DMA (0 – 16 MB)

ISA DMA přenosy

Normal (16 – 896 MB)

běžná paměť

High (> 896 MB)

paměť nemapovatelná 1:1 do virtuálního adresního prostoru kernelu

používá se převážně pro user space stránky

Paměťové zóny (2)

popis zóny (linux/mmzone.h)

typedef struct zone_struct {

spinlock_t lock;

unsigned long free_pages;

unsigned long pages_min, pages_low, pages_high;

int need_balance;

free_area_t free_area[MAX_ORDER];

wait_queue_head_t *wait_table;

unsigned long wait_table_size, wait_table_shift;

struct pglist_data *zone_pgdat;

struct page *zone_mem_map;

unsigned long zone_start_paddr;

unsigned long zone_start_mapnr;

char *name;

unsigned long size;

} zone_t;

Adresní prostor

virtuální adresní prostor z pohledu kernelu

ploché mapování

i386: 3/1 GB split

0 – 3 GB (0 – PAGE_OFFSET-1)

user space mapping

KERNEL

USER

mapovaná paměť kernelu

vmalloc()

3 – 4 GB (PAGE_OFFSET – 0xFFFFFFFF)

1:1 mapování fyzické paměti

kmalloc()

fyzicky kernel uložen od 2. MB paměti

Přístup k paměti

segmentace (např. i386)

nevyužita

výchozí segmenty

0x10	kernel code

0x18	kernel data/stack

0x23	user space code

0x2b	user space data/stack

kód odpovídá CS, data/stack odpovídají DS, SS (ES, ...)

pokrývají celé 4 GB

všechny segmenty v GDT

LDT se přímo nepoužívají, sys_modify_ldt pro práci s nimi (Wine)

dříve každý proces měl vlastní TSS

Přístup k paměti (2)

stránkování

interně: 3úrovňové

page global directory

page middle directory

page table

makra

PAGE_SHIFT, PMD_SHIFT, PGDIR_SHIFT

i386: 2úrovňové (10:10:12)

page global directory jednopoložková

PAE: 2:9:9:12

Přístup k paměti (3)

GLOBAL

MIDDLE

TABLE

OFFSET

BITS_PER_LONG

PAGE_SHIFT

PMD_SHIFT

PGDIR_SHIFT

Přístup k paměti (4)

popis stránky

typedef struct page {

struct page *next;

struct page *prev;

struct inode *inode;

unsigned long offset;

struct page *next_hash;

atomic_t count;

unsigned long flags;

struct wait_queue *wait;

struct page **prev_hash;

struct buffer_head *buffers;

} mem_map_t;

všechny stránky v poli mem_map (MAP_NR)

Buddy system

alokátor paměti s granularitou stránek

udržuje seznamy volných stránek velikosti odpovídajících jednotlivým řádům (počet stránek je 2order)

pole typu free_area_struct

bitmapy použitých bloků

zvlášť seznamy pro zóny DMA, Normal, High

stránky jsou souvislé ve fyzické paměti

vrací virtuální adresu

pro převod makra __pa(), __va()

Buddy system (2)

alokace (mm/page_alloc.c)

get_zeroed_page(gfp_mask)

__get_free_page(gfp_mask)

__get_free_pages(gfp_mask, order)

velikost v log2 počtu stránek, limit typicky 2 MB

flagy

GFP_KERNEL

v kontextu procesu, může blokovat

GFP_ATOMIC

v kontextu přerušení, neblokuje

GFP_BUFFER

pro bufferovou cache, může blokovat, neprovádí flush dirty stranek cache

GFP_USER

v kontextu procesu, může blokovat, low-priority

Buddy system (3)

GFP_HIGHUSER

jako GFP_USER, ze zóny High

__GFP_DMA

modifikátor pro zónu DMA

dříve __get_dma_pages()

__GFP_HIGHMEM

modifikátor pro zónu High

__GFP_IO

modifikátor povolující odswapovat, povoluje blokování

dealokace

free_page(addr)

free_pages(addr, order)

hodnoty se nekontrolují

Slab allocator

alokace paměťových oblastí předem daných vlastností (mm/slab.c)

délka

konstruktor, destruktor

v kernelu se nepoužívají

cacheování již alokovaných objektů

objekty stejného typu se seskupují do cachí

cache jsou pojmenovány, viz /proc/slabinfo

cache odkazuje na slab

jedna nebo více stránek (spojitých) obsahující alokované a volné objekty

Slab allocator (2)

kmem_cache_t

kmem_slab_t

pro objekty menší než 512 B uložen na konci slabu

stránky s objekty se dealokují jen explicitně

při nedostatku paměti

CACHE

CACHE

SLAB

SLAB

SLAB

SLAB

SLAB

SLAB

OBJECT

OBJECT

OBJECT

OBJECT

OBJECT

OBJECT

OBJECT

OBJECT

OBJECT

Slab allocator (3)

kmem_cache_t

kmem_slab_t

kmem_cache_t

kmem_cache_t

kmem_slab_t

kmem_slab_t

kmem_slab_t

kmem_slab_t

kmem_slab_t

kmem_slab_t

Slab allocator (4)

druhy cachí

general

pro potřeby alokátoru (cache_cache, cache_slabp, cache_sizes)

specific

kmem_cache_create(name, size, offset, flags, ctor, dtor)

vytvoření nové specifické cache, bez slabů

SLAB_NOREAP, SLAB_HWCACHE_ALIGN, SLAB_CACHE_DMA

kmem_cache_alloc(*cachep, flags)

alokace nového objektu ve slabu

SLAB_NOIO, SLAB_ATOMIC, SLAB_DMA

kmem_cache_free()

kmalloc()

Alokace fyzicky souvislé paměti (mm/slab.c)

využívá slab allocator

bloky velikosti mocniny dvojky, obvykle od 32 B do 128 KB

size-32, size-32(DMA), ...

flagy shodné jako pro get_free_page()

paměť není inicializovaná

dealokace

kfree()

vmalloc()

Alokace mapované paměti (mm/vmalloc.c)

fyzicky nesouvislá, souvislá ve virtuální paměti

jednotlivé stránky pomocí __get_free_page()

nelze použít v kontextu přerušení (GFP_KERNEL)

granularita je po stránkách

efektivní jen pro více než jednu stránku

velikost omezena fyzickou pamětí

dealokace

vfree()

Alokace během bootu

alokace velkého bloku fyzicky souvislé paměti

trik s mem=

reserve_bootmem(addr, size)

označí část paměti jako reserved

alloc_bootmem(size)

alokace libovolné nezarovnané oblasti

alloc_bootmem_pages(size)

alokace oblasti zarovnané na stránky

Alokace paměti pro user space

mapování specifické procesu

popsáno regiony virtuální paměti

bázová adresa, délka, přístupová práva

code, init data, data, stack, shared code, shared data, stack

nepřekrývající

slučování přilehlých (se stejnými právy)

kernel udržuje ve spojovém seznamu nebo AVL stromu (pro více než AVL_MIN_MAP_COUNT, typicky 32)

klasický POSIXový syscall brk se převádí na mremap a munmap regionu haldy

demand paging

copy-on-write

Odkazy

[1] Bovet, Cesati: Understanding the Linux Kernel (O'Reilly)

[2] Nayani, Gorman, de Castro: Memory management in Linux (LKDP)

[3] Gorman: Understanding The Linux Virtual Memory Manager (LKDP)

[4] Gorman: Code Commentary On The Linux Virtual Memory Manager (LKDP)

2004-10-31T19:04:29