Liberação de Memória no Kernel Linux com kfree

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");

Tags: Linux Kernel Memory Management kfree slab allocator kmalloc

Publicado em 7-11 23:07