Gerenciamento de Memória
Leandro Marzulo
Roteiro










Páginas
Zonas
Operações com Páginas
kmalloc()
vmalloc()
Slab Layer
Alocação estática na Pilha
High Memory Mappings
Alocação “Per-CPU”
Qual método de alocação usar?
Roteiro










Páginas
Zonas
Operações com Páginas
kmalloc()
vmalloc()
Slab Layer
Alocação estática na Pilha
High Memory Mappings
Alocação “Per-CPU”
Qual método de alocação usar?
Páginas

Unidade básica de Gerenciamento de memória
Tamanho relacionado com a arquitetura (4KB ou 8 KB)

Struct page <linux/mm.h>

struct page {
page_flags_t flags; //Status da página
//<linux/page-flags.h>
atomic_t _count;
//Contador de referências
//page_count()
atomic_t _mapcount;
unsigned long private;
struct address_space *mapping; //cache
pgoff_t index;
struct list_head lru;
void *virtual;
//endereço virtual
//NULL para HIGH MEM
};
Páginas






Struct page - páginas físicas
Estrutura descreve algo transiente
Descrição da memória física
Saber quais são as páginas livres
Saber quem é o dono de cada página
ocupada
TAMANHO OCUPADO PELAS STRUCTS
1GB = 262144 páginas (de 4KB)
Struct page = 40 bytes
40 * 262144 = 10485760 bytes = 10MB
Menos de 1% da memória total
Roteiro










Páginas
Zonas
Operações com Páginas
kmalloc()
vmalloc()
Slab Layer
Alocação estática na Pilha
High Memory Mappings
Alocação “Per-CPU”
Qual método de alocação usar?
Zonas



Arquiteturas que fazem DMA apenas em alguns
endereços
Arquiteturas que podem endereçar fisicamente
mais memória do que podem endereçar
virtualmente
Zonas <linux/mmzone.h>
Zona
Descrição
ZONE_DMA
Páginas que podem ser
usadas para DMA
ZONE_NORMAL
Páginas endereçadas
normalmente
ZONE_HIGHMEM
Páginas mapeadas
dinamicamente
L. Física (x86)
< 16MB
Entre 16MB e
896MB
> 896MB
Zonas
Pooling independente
 Alocação para DMA só pode vir da
ZONE_DMA
 Alocação normal vem,
preferencialmente de ZONE_NORMAL,
mas pode vir de ZONE_DMA

ZONAS

Struct zone <linux/mmzone.h>
struct zone {
spinlock_t
unsigned long
unsigned long
unsigned long
unsigned long
lock; //Proteção contra
//acessos concorrentes
free_pages; //num de pgs. livres
pages_min; //kernel tenta manter
//o mín livre (swap)
pages_low;
pages_high;
.
.
.
unsigned long
char
unsigned long
unsigned long
};
zone_start_pfn;
*name; //nome da zona – “DMA”
//”Normal” e “HighMem”
//(inicializado no boot)
// <mm/page_aloc.c>
spanned_pages;
present_pages;
Roteiro










Páginas
Zonas
Operações com Páginas
kmalloc()
vmalloc()
Slab Layer
Alocação estática na Pilha
High Memory Mappings
Alocação “Per-CPU”
Qual método de alocação usar?
Operações com Páginas

Pegando páginas <linux/gfp.h>
struct page * alloc_pages(unsigned int gfp_mask,
unsigned int order) //Aloca 2order páginas contíguas
void * page_address(struct page *page)
//retorna ponteiro para o endereço lógico
unsigned long __get_free_pages(unsigned int
gfp_mask, unsigned int order)
//retorna o endereço lógico
/* PARA ALOCAR UMA PÁGINA */
struct page * alloc_page(unsigned int gfp_mask)
unsigned long __get_free_page(unsigned int gfp_mask)
Operações com Páginas

Pegando uma página Zerada
unsigned long get_zeroed_page(unsigned int gfp_mask)

Liberando páginas
void __free_pages(struct page *page, unsigned int
order)
void free_pages(unsigned long addr, unsigned int
order)
void free_page(unsigned long addr)
Operações com Páginas

Exemplo
unsigned long page;
page = __get_free_pages(GFP_KERNEL, 3);
if (!page) {
// TRATAR ERRO – MEMÓRIA INSUFICIENTE
return ENOMEM;
}
.
.
.
free_pages(page, 3);
Roteiro










Páginas
Zonas
Operações com Páginas
kmalloc()
vmalloc()
Slab Layer
Alocação estática na Pilha
High Memory Mappings
Alocação “Per-CPU”
Qual método de alocação usar?
Kmalloc()


Interface para obter memória em bytes ao invés
de páginas
= malloc + flags
Declaração <linux/slab.h>

void * kmalloc(size_t size, int flags)
/* retorna um ponteiro para região fisicamente
contínua de no mínimo “size” bytes (alocação é feita
em páginas na realidade)*/
 Exemplo
struct dog *ptr;
ptr = kmalloc(sizeof(struct dog), GFP_KERNEL);
if (!ptr)
/* Erro ... */
Kmalloc()

Flags <linux/gfp.h>




Action Modifiers – como o kernel deve alocar a
memória requisitada (Manipuladores de
interrupção  kernel não pode “dormir”)
Zone Modifiers – de onde o kernel deve alocar
a memória requisitada
Type flags – combinação de “Action Modifiers” e
“Zone Modifiers” necessários para um
determinado tipo de alocação
Exemplo
ptr = kmalloc(size, __GFP_WAIT | __GFP_IO |
__GFP_FS);
Kmalloc()

Action Modifiers
Flag
Descrição
__GFP_WAIT
The allocator can sleep.
__GFP_HIGH
The allocator can access emergency pools.
__GFP_IO
The allocator can start disk I/O.
__GFP_FS
The allocator can start filesystem I/O.
__GFP_COLD
The allocator should use cache cold pages.
__GFP_NOWARN
The allocator will not print failure warnings.
__GFP_REPEAT
The allocator will repeat the allocation if it
fails, but the allocation can potentially fail.
__GFP_NORMAL
The allocator will indefinitely repeat the
allocation. The allocation cannot fail.
__GFP_NORETRY
The allocator will never retry if the
allocation fails.
__GFP_NO_GROW
Used internally by the slab layer.
__GFP_COMP
Add compound page metadata. Used internally by
the hugetlb code.
Kmalloc()

Zone Modifiers


Default – ZONE_NORMAL
__GFP_HIGHMEM não pode ser usado em
__get_free_pages() ou kmalloc(). É usado com
alloc_pages()
Flag
Descrição
__GFP_DMA
Aloca memória apenas da ZONE_DMA.
__GFP_HIGHMEM Aloca memória da ZONe_HIGHMEM ou
ZONE_NORMAL.
Kmalloc()

Type Flags
Flag
Descrição
GFP_ATOMIC
Não pode dormir.
GFP_NOIO
Pode bloquear, mas não pode iniciar I/O no
disco.
GFP_NOFS
Pode bloquear e fazer I/O no disco, mas não
pode iniciar uma operação no filesystem. Usado
em código do filesystem onde não se pode
iniciar outra operação de filesystem.
GFP_KERNEL
Alocação normal. Usada no contexto do processo
onde é seguro “dormir”. O kernel fará de tudo
para obter a memória requerida.
GFP_USER
Alocação normal. Usada para alocar memória para
processos do usuário.
GFP_HIGHUSER
Alocação na ZONE_HIGHMEM que pode bloquear.
Usada para alocar memória para processos do
usuário.
GFP_DMA
Alocação na ZONE_DMA.
Kmalloc()

Type Flags – Composição
Flag
Modifiers Flags
GFP_ATOMIC
__GFP_HIGH
GFP_NOIO
__GFP_WAIT
GFP_NOFS
(__GFP_WAIT | __GFP_IO)
GFP_KERNEL
(__GFP_WAIT | __GFP_IO | __GFP_FS)
GFP_USER
(__GFP_WAIT | __GFP_IO | __GFP_FS)
GFP_HIGHUSER
(__GFP_WAIT | __GFP_IO | __GFP_FS |
__GFP_HIGHMEM)
GFP_DMA
__GFP_DMA
Kmalloc()

Flags – Uso
Situação
Solução
Contexto do Processo. Pode
“dormir”
GFP_KERNEL
Contexto do Processo. Não
pode “dormir”
GFP_ATOMIC ou
GFP_KERNEL antes (qdo
pode “dormir”
Manipuladores de
Interrupção
GFP_ATOMIC
Softirq
GFP_ATOMIC
Tasklet
GFP_ATOMIC
DMA e pode “dormir”
(GFP_DMA | GFP_KERNEL)
DMA e não pode “dormir”
(GFP_DMA | GFP_ATOMIC)
Kmalloc()

E para liberar a memória?

Kfree() <linuxslab.h>
void kfree(const void *ptr)

Exemplo
char *buf;
buf = kmalloc(BUF_SIZE, GFP_ATOMIC);
if (!buf)
/* error allocting memory ! */
.
.
.
kfree(buf);
Roteiro










Páginas
Zonas
Operações com Páginas
kmalloc()
vmalloc()
Slab Layer
Alocação estática na Pilha
High Memory Mappings
Alocação “Per-CPU”
Qual método de alocação usar?
Vmalloc()




Semelhante ao kmalloc(), porém aloca
memória virtualmente contígua e não
necessariamente fisicamente contígua
A maior parte do kernel usa kmalloc()
Performance do kmalloc é melhor (TLB)
Declaração <linux/vmalloc.h>
<mm/vmalloc.c>
void * vmalloc(unsigned long size)

Para liberar a memória
void vfree(void *addr)
Roteiro










Páginas
Zonas
Operações com Páginas
kmalloc()
vmalloc()
Slab Layer
Alocação estática na Pilha
High Memory Mappings
Alocação “Per-CPU”
Qual método de alocação usar?
Slab Layer



Free Lists
Problema: Controle Global – Liberar memória
Conceito de Slab Alocator







Estruturas de dados frequentemente usadas tendem a
ser alocadas e liberadas constantemente – CACHE
Fragmentação de memória – as free lists na CACHE são
arrumadas continuamentea
Melhoria de performance
O alocador conhece o tamanho do objeto, página e da
cache – melhores decisões
Parte da cache é implementada por processador (SMP
lock desnecessário)
Se o alocador é NUMA-aware, ele pode procurar alocar
memória do nó que requisitou
Os objetos armazenados podem ser marcados para
prevenir que múltiplos objetos sejam mapeados na
mesma linha de cache
Slab Layer

Design
Slab Layer
Uma cache por tipo de objeto
 Kmalloc() usa uma família de caches
de propósito geral
 Slabs compostas de uma ou mais
paginas fisicamente contíguas
 Cada Slab contem um número de
objetos
 Slab possui 3 estados: full, partial ou
empty

Slab Layer

Struct slab
struct slab {
struct list_head list; /* full, partial, or empty list */
unsigned long colouroff; /* offset for the slab coloring */
void *s_mem; /* first object in the slab */
unsigned int inuse; /* allocated objects in the slab */
kmem_bufctl_t free; /* first free object, if any */
};

Criação de slabs feita em
__get_free_pages()
Slab Layer

Exemplo
static inline void * kmem_getpages(kmem_cache_t
*cachep, unsigned long flags) {
void *addr;
flags |= cachep->gfpflags; addr = (void*)
__get_free_pages(flags, cachep->gfporder);
return addr;
}

Liberando memória (low mem ou
cache destruida)
kmem_freepages()
 free_pages()
Slab Layer

Criação de cache
kmem_cache_t * kmem_cache_create(
const char *name, //nome da cache
size_t size, //tamanho de cada elemento
size_t align, //offset
unsigned long flags, //comportamento da cache
void (*ctor)(void*, kmem_cache_t *, unsigned long),
//construtor
void (*dtor)(void*, kmem_cache_t *, unsigned long))
//destrutor
Flag
Descrição
SLAB_NO_REAP
Slab Layer não faz reap automático
SLAB_HWCACHE_ALIGN
Alinhar cada objeto com uma linha de cache
SLAB_MUST_HWCACHE_ALIGN
Força alinhamento na cache dos objetos
SLAB_POISON
Prenche a slab com (a5a5a5a5)
SLAB_RED_ZONE
Ajuda na detecção de buffer overruns
SLAB_PANIC
Quando a alocação não pode falhar
SLAB_CACHE_DMA
Para usar DMA
Slab Layer

Destruindo a cache
Invocada pelo shutdown de modulos que
criam suas próprias caches
 Não pode ser chamada no contexto de
interrupção (pode dormir)
 Todas as slabs devem estar vazias
 Ninguém pode acessar a cache durante
ou depois (sincronização)

int kmem_cache_destroy(kmem_cache_t *cachep)
Slab Layer

Alocando um objeto da cache
void * kmem_cache_alloc(kmem_cache_t *cachep, int flags)

Liberando um objeto
void kmem_cache_free(kmem_cache_t *cachep, void *objp)
Roteiro










Páginas
Zonas
Operações com Páginas
kmalloc()
vmalloc()
Slab Layer
Alocação estática na Pilha
High Memory Mappings
Alocação “Per-CPU”
Qual método de alocação usar?
Alocação Estática na Pilha
Pilha pequena e estática
 Duas formas

2 páginas por processo
 1 página por processo + 1 para
manipuladores de interrupção

Roteiro










Páginas
Zonas
Operações com Páginas
kmalloc()
vmalloc()
Slab Layer
Alocação estática na Pilha
High Memory Mappings
Alocação “Per-CPU”
Qual método de alocação usar?
High Memory Mappings

Mapeamento permanente (pode
dormir)
void *kmap(struct page *page)
void kunmap(struct page *page)

Mapeamento temporário
void *kmap_atomic(struct page *page, enum km_type type)
void kunmap_atomic(void *kvaddr, enum km_type type)
Roteiro










Páginas
Zonas
Operações com Páginas
kmalloc()
vmalloc()
Slab Layer
Alocação estática na Pilha
High Memory Mappings
Alocação “Per-CPU”
Qual método de alocação usar?
Alocação “Per-CPU”

Razões para usar
Evitar Locks
 Reduzir Invalidação de cache

Alocação “Per-CPU”
Problemas com preempção do kernel



Código pode ser reescalonado em outro
processador (variável CPU não é mais válida
Se outra task faz preempção pode acessar o
my_percpu concorrentemente
Interface Antiga
unsigned long my_percpu[NR_CPUS];
int cpu; cpu = get_cpu(); //pega o proc e desablita preemp
my_percpu[cpu]++;
smp_processor_id(); //não desabilita preemp
printk("my_percpu on cpu=%d is %lu\n", cpu,
my_percpu[cpu]); put_cpu(); //habilita preemp
Alocação “Per-CPU”

Nova Interface
DEFINE_PER_CPU(type, name);
DECLARE_PER_CPU(type, name);
get_cpu_var(name)++;
put_cpu_var(name); /* preemption */
per_cpu(name, cpu)++;
void *alloc_percpu(type); /* a macro */
void *__alloc_percpu(size_t size, size_t align);
void free_percpu(const void *);
get_cpu_ptr(ptr); /* return a void pointer to this
processor's copy of ptr */
put_cpu_ptr(ptr); /* done; enable kernel preemption */
per_cpu_ptr(ptr, cpu);
Roteiro










Páginas
Zonas
Operações com Páginas
kmalloc()
vmalloc()
Slab Layer
Alocação estática na Pilha
High Memory Mappings
Alocação “Per-CPU”
Qual método de alocação usar?
Qual método de alocação usar?
Método
Descrição
Kmalloc()
Páginas fisicamente
contíguas
alloc_pages()
High Memory
Vmalloc()
Lógicamente
Contíguas apenas
Slab cache
Criação e destruição
de muitas estruturas
grandes
OBRIGADO!!!!!!
Download

Gerenciamento de Memória