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!!!!!!