No kernel Linux, a função kfree é usada para liberar memória alocada dinamicamente por funções como kmalloc, kzalloc ou vmalloc. Ela devolve a memória ao sistema, prevenindo vazamentos e otimizando o gerenciamento de recursos.
Quando um módulo do kernel requer memória temporária, ele invoca kmalloc ou kzalloc (que aloca e zera a memória). Após o uso, kfree deve ser chamado para liberar essa memória.
O protótipo de kfree está definido em include/linux/slab.h:
void kfree(const void *objp);
Aqui, objp é um ponteirro para o bloco de memória a ser liberado. kfree verifica o ponteiro, identifica o tamanho e tipo do bloco através de metadados, e o retorna ao pool de memória adequado.
O processo de liberação segue etapas específicas:
- Verifica se o ponteiro é
NULL; se for, retorna imediatamente. - Determina as características do bloco usando informações de cabeçalho armazenadas na alocação.
- Libera o bloco do respectivo pool de memória.
- Tenta mesclar o bloco com vizinhos livres para reduzir fragmentação.
- Atualiza estatísticas de uso de memória no kernel.
Implementação de kfree
O código fonte de kfree no kernel segue esta lógica:
void kfree(const void *block)
{
struct page *pagina_mem;
rastreamento_kfree(_RET_IP_, block);
if (unlikely(ZERO_OR_NULL_PTR(block)))
return;
kmemleak_free(block);
pagina_mem = virt_to_page(block);
if (PageSlab(pagina_mem)) {
int alinhamento = max_t(size_t, ARCH_KMALLOC_MINALIGN, ARCH_SLAB_MINALIGN);
unsigned int *cabecalho = (unsigned int *)(block - alinhamento);
slob_free(cabecalho, *cabecalho + alinhamento);
} else
__free_pages(pagina_mem, compound_order(pagina_mem));
}
EXPORT_SYMBOL(kfree);
Este código converte o endereço virtual em uma estrutura page, que representa uma unidade física de memória. A liberação é feita via __free_pages para memórias de página completa ou slob_free para alocações menores gerenciadas pelo alocador slab.
Exemplos Práticos
Alocação e Liberação Básica
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
static int __init modulo_init(void)
{
void *espaco_memoria = kmalloc(1024, GFP_KERNEL);
if (!espaco_memoria) {
pr_err("Falha na alocação de memória\n");
return -ENOMEM;
}
// Utilizar espaco_memoria para operações...
kfree(espaco_memoria);
return 0;
}
static void __exit modulo_exit(void) { }
module_init(modulo_init);
module_exit(modulo_exit);
MODULE_LICENSE("GPL");
Gerenciamento de Erros em Alocações
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
static int __init modulo_init(void)
{
void *buffer_limpo = kzalloc(1024, GFP_KERNEL);
if (!buffer_limpo) {
pr_err("Falha ao alocar memória zerada\n");
return -ENOMEM;
}
// Processar dados em buffer_limpo...
if (erro_detectado) {
kfree(buffer_limpo);
return -EFAULT;
}
kfree(buffer_limpo);
return 0;
}
static void __exit modulo_exit(void) { }
module_init(modulo_init);
module_exit(modulo_exit);
MODULE_LICENSE("GPL");
Manipulação de Listas Encadeadas com kfree
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/list.h>
struct item_dado {
int conteudo;
struct list_head nodo;
};
static LIST_HEAD(cabeca_lista);
static int __init modulo_init(void)
{
struct item_dado *elemento;
struct list_head *iterador, *proximo;
elemento = kmalloc(sizeof(*elemento), GFP_KERNEL);
if (!elemento) {
pr_err("Falha ao alocar memória para item\n");
return -ENOMEM;
}
elemento->conteudo = 100;
INIT_LIST_HEAD(&elemento->nodo);
list_add(&elemento->nodo, &cabeca_lista);
list_for_each_safe(iterador, proximo, &cabeca_lista) {
elemento = list_entry(iterador, struct item_dado, nodo);
// Usar elemento->conteudo...
list_del(iterador);
kfree(elemento);
}
return 0;
}
static void __exit modulo_exit(void) { }
module_init(modulo_init);
module_exit(modulo_exit);
MODULE_LICENSE("GPL");